Skip to content

Commit 102814a

Browse files
authored
Merge pull request #85 from afsar-dev/dev
new navbar added
2 parents b1b247c + c14c411 commit 102814a

17 files changed

+538
-200
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
},
1111
"dependencies": {
1212
"@gsap/react": "^2.1.2",
13+
"@left4code/svg-renderer": "^1.0.4",
1314
"@mdx-js/loader": "^3.1.0",
1415
"@mdx-js/react": "^3.1.0",
1516
"@next/mdx": "^15.3.3",

public/r/future-button.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,17 @@
1313
"files": [
1414
{
1515
"path": "./src/components/nurui/future-button-demo.tsx",
16-
"content": "\"use client\";\nimport { Button } from \"@/components/nurui/future-button\";\nimport { ShoppingCart } from \"lucide-react\";\n\nexport default function FutureButtonDemo() {\n return (\n <div className=\"flex justify-center py-20\">\n <Button variant=\"destructive\">\n <ShoppingCart className=\"w-4 h-4 mr-2\" />\n Purchase Item\n </Button>\n </div>\n );\n}\n",
16+
"content": "\"use client\";\nimport { ShoppingCart } from \"lucide-react\";\nimport FutureButton from \"./future-button\";\n\nexport default function FutureButtonDemo() {\n return (\n <div className=\"flex justify-center py-20\">\n <FutureButton>\n <ShoppingCart className=\"w-4 h-4 mr-2\" />\n Purchase Item\n </FutureButton>\n </div>\n );\n}\n",
1717
"type": "registry:component"
1818
},
1919
{
2020
"path": "./src/components/nurui/future-button.tsx",
21-
"content": "import type React from \"react\";\nimport { Frame } from \"@/components/nurui/future-frame\";\nimport { twMerge } from \"tailwind-merge\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nconst buttonVariants = cva(\n [\n \"group font-black mb-2 relative px-8 py-1 cursor-pointer transition-all [&:hover_svg]:drop-shadow-xl outline-none\",\n \"[&>span]:relative [&>span]:flex [&>span]:items-center [&>span]:justify-center [&>span]:group-hover:text-shadow-lg\",\n ],\n {\n variants: {\n variant: {\n default:\n \"[--color-frame-1-stroke:theme(colors.blue.500)] [--color-frame-1-fill:theme(colors.blue.500/0.22)] [--color-frame-2-stroke:theme(colors.blue.500)] [--color-frame-2-fill:theme(colors.blue.500/0.1)] text-blue-100 [&:hover_svg]:drop-shadow-blue-500/50\",\n accent:\n \"[--color-frame-1-stroke:theme(colors.purple.500)] [--color-frame-1-fill:theme(colors.purple.500/0.4)] [--color-frame-2-stroke:theme(colors.purple.500)] [--color-frame-2-fill:theme(colors.purple.500/0.2)] text-purple-100 [&:hover_svg]:drop-shadow-purple-500/50\",\n destructive:\n \"[--color-frame-1-stroke:theme(colors.red.500)] [--color-frame-1-fill:theme(colors.red.500/0.22)] [--color-frame-2-stroke:theme(colors.red.500)] [--color-frame-2-fill:theme(colors.red.500/0.1)] text-red-100 [&:hover_svg]:drop-shadow-red-500/50\",\n secondary:\n \"[--color-frame-1-stroke:theme(colors.gray.500)] [--color-frame-1-fill:theme(colors.gray.500/0.15)] [--color-frame-2-stroke:theme(colors.gray.500)] [--color-frame-2-fill:theme(colors.gray.500/0.1)] text-gray-100 [&:hover_svg]:drop-shadow-gray-500/50\",\n success:\n \"[--color-frame-1-stroke:theme(colors.green.500)] [--color-frame-1-fill:theme(colors.green.500/0.22)] [--color-frame-2-stroke:theme(colors.green.500)] [--color-frame-2-fill:theme(colors.green.500/0.1)] text-green-100 [&:hover_svg]:drop-shadow-green-500/50\",\n },\n shape: {\n default: \"\",\n flat: \"[--color-frame-2-stroke:transparent] [--color-frame-2-fill:transparent]\",\n simple: \"ps-8 pe-6\",\n \"tab-left\": \"\",\n \"tab-center\": \"\",\n \"tab-right\": \"\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n shape: \"default\",\n },\n },\n);\n\nfunction Button({\n className,\n children,\n variant = \"default\",\n shape = \"default\",\n customPaths,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n customPaths?: string[];\n }) {\n return (\n <button\n {...props}\n className={twMerge(buttonVariants({ variant, shape, className }))}\n >\n <div className=\"absolute inset-0 -mb-2\">\n {!customPaths && (shape == \"default\" || shape == \"flat\") && (\n <Frame\n paths={JSON.parse(\n '[{\"show\":true,\"style\":{\"strokeWidth\":\"1\",\"stroke\":\"var(--color-frame-1-stroke)\",\"fill\":\"var(--color-frame-1-fill)\"},\"path\":[[\"M\",\"17\",\"0\"],[\"L\",\"180\",\"0\"],[\"L\",\"200\",\"9.5\"],[\"L\",\"182\",\"34\"],[\"L\",\"4\",\"34\"],[\"L\",\"0\",\"25\"],[\"L\",\"17\",\"0\"]]},{\"show\":true,\"style\":{\"strokeWidth\":\"1\",\"stroke\":\"var(--color-frame-2-stroke)\",\"fill\":\"var(--color-frame-2-fill)\"},\"path\":[[\"M\",\"9\",\"34\"],[\"L\",\"178\",\"34\"],[\"L\",\"175\",\"40\"],[\"L\",\"12\",\"40\"],[\"L\",\"9\",\"34\"]]}]',\n )}\n />\n )}\n {!customPaths && shape == \"simple\" && (\n <Frame\n paths={JSON.parse(\n '[{\"show\":true,\"style\":{\"strokeWidth\":\"1\",\"stroke\":\"var(--color-frame-1-stroke)\",\"fill\":\"var(--color-frame-1-fill)\"},\"path\":[[\"M\",\"17\",\"0\"],[\"L\",\"200\",\"0\"],[\"L\",\"200\",\"34\"],[\"L\",\"3\",\"34\"],[\"L\",\"0\",\"24\"],[\"L\",\"17\",\"0\"]]},{\"show\":true,\"style\":{\"strokeWidth\":\"1\",\"stroke\":\"var(--color-frame-2-stroke)\",\"fill\":\"var(--color-frame-2-fill)\"},\"path\":[[\"M\",\"8\",\"34\"],[\"L\",\"195\",\"34\"],[\"L\",\"193\",\"40\"],[\"L\",\"10\",\"40\"],[\"L\",\"8\",\"34\"]]}]',\n )}\n />\n )}\n {customPaths?.map((customPath, customPathKey) => {\n return <Frame key={customPathKey} paths={JSON.parse(customPath)} />;\n })}\n </div>\n <span>{children}</span>\n </button>\n );\n}\n\nexport { Button };\n",
21+
"content": "import { Frame } from \"@/components/nurui/frame\";\nimport { twMerge } from \"tailwind-merge\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\n// 🎨 Theme colors — no CSS variables, pure hex/rgba\nconst COLORS = {\n default: {\n stroke1: \"#4f46e5\",\n fill1: \"rgba(79,70,229,0.22)\",\n stroke2: \"#4f46e5\",\n fill2: \"rgba(79,70,229,0.1)\",\n text: \"#ffffff\",\n },\n accent: {\n stroke1: \"#f97316\",\n fill1: \"rgba(249,115,22,0.4)\",\n stroke2: \"#f97316\",\n fill2: \"rgba(249,115,22,0.2)\",\n text: \"#ffffff\",\n },\n destructive: {\n stroke1: \"#dc2626\",\n fill1: \"rgba(220,38,38,0.22)\",\n stroke2: \"#dc2626\",\n fill2: \"rgba(220,38,38,0.1)\",\n text: \"#ffffff\",\n },\n secondary: {\n stroke1: \"#64748b\",\n fill1: \"rgba(100,116,139,0.15)\",\n stroke2: \"#64748b\",\n fill2: \"rgba(100,116,139,0.1)\",\n text: \"#ffffff\",\n },\n success: {\n stroke1: \"#16a34a\",\n fill1: \"rgba(22,163,74,0.22)\",\n stroke2: \"#16a34a\",\n fill2: \"rgba(22,163,74,0.1)\",\n text: \"#ffffff\",\n },\n};\n\nconst buttonVariants = cva(\n \"group font-bold mb-2 relative px-8 py-2 cursor-pointer transition-all outline-none [&>span]:relative [&>span]:flex [&>span]:items-center [&>span]:justify-center\",\n {\n variants: {\n shape: {\n default: \"\",\n flat: \"\",\n simple: \"ps-8 pe-6\",\n },\n },\n defaultVariants: {\n shape: \"default\",\n },\n },\n);\n\nfunction FutureButton({\n className,\n children,\n shape = \"default\",\n enableBackdropBlur = false,\n enableViewBox = false,\n customPaths,\n textColor,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n customPaths?: string[];\n enableBackdropBlur?: boolean;\n enableViewBox?: boolean;\n bgColor?: string;\n textColor?: string;\n }) {\n const colors = COLORS.default;\n\n return (\n <button\n {...props}\n style={{\n color: textColor || colors.text,\n }}\n className={twMerge(buttonVariants({ shape, className }))}\n >\n <div className=\"absolute inset-0 -mb-2\">\n {!customPaths && (shape === \"default\" || shape === \"flat\") && (\n <Frame\n enableBackdropBlur={enableBackdropBlur}\n enableViewBox={enableViewBox}\n paths={[\n {\n show: true,\n style: {\n strokeWidth: \"1\",\n stroke: colors.stroke1,\n fill: colors.fill1,\n },\n path: [\n [\"M\", \"17\", \"0\"],\n [\"L\", \"100% - 7\", \"0\"],\n [\"L\", \"100% + 0\", \"0% + 9.5\"],\n [\"L\", \"100% - 18\", \"100% - 6\"],\n [\"L\", \"4\", \"100% - 6\"],\n [\"L\", \"0\", \"100% - 15\"],\n [\"L\", \"17\", \"0\"],\n ],\n },\n {\n show: true,\n style: {\n strokeWidth: \"1\",\n stroke: colors.stroke2,\n fill: colors.fill2,\n },\n path: [\n [\"M\", \"9\", \"100% - 6\"],\n [\"L\", \"100% - 22\", \"100% - 6\"],\n [\"L\", \"100% - 25\", \"100% + 0\"],\n [\"L\", \"12\", \"100% + 0\"],\n [\"L\", \"9\", \"100% - 6\"],\n ],\n },\n ]}\n />\n )}\n\n {!customPaths && shape === \"simple\" && (\n <Frame\n enableBackdropBlur={enableBackdropBlur}\n enableViewBox={enableViewBox}\n paths={[\n {\n show: true,\n style: {\n strokeWidth: \"1\",\n stroke: colors.stroke1,\n fill: colors.fill1,\n },\n path: [\n [\"M\", \"17\", \"0\"],\n [\"L\", \"100% - 0\", \"0\"],\n [\"L\", \"100% - 0\", \"100% - 6\"],\n [\"L\", \"0% + 3\", \"100% - 6\"],\n [\"L\", \"0% - 0\", \"100% - 16\"],\n [\"L\", \"17\", \"0\"],\n ],\n },\n {\n show: true,\n style: {\n strokeWidth: \"1\",\n stroke: colors.stroke2,\n fill: colors.fill2,\n },\n path: [\n [\"M\", \"8\", \"100% - 6\"],\n [\"L\", \"100% - 5\", \"100% - 6\"],\n [\"L\", \"100% - 7\", \"100% - 0\"],\n [\"L\", \"10\", \"100% - 0\"],\n [\"L\", \"8\", \"100% - 6\"],\n ],\n },\n ]}\n />\n )}\n\n {customPaths?.map((customPath, i) => (\n <Frame key={i} paths={JSON.parse(customPath)} />\n ))}\n </div>\n <span>{children}</span>\n </button>\n );\n}\n\nexport default FutureButton;\n",
2222
"type": "registry:component"
2323
},
2424
{
25-
"path": "./src/components/nurui/future-frame.tsx",
26-
"content": "\"use client\";\n\nimport type React from \"react\";\n\nimport { useRef, useEffect } from \"react\";\nimport { twMerge } from \"tailwind-merge\";\n// import type { Paths } from \"@/types/frame\"\n\ntype PathCommand = [\"M\" | \"L\", string, string];\n\ninterface PathProps {\n show: boolean;\n style: {\n strokeWidth: string;\n stroke: string;\n fill: string;\n };\n path: PathCommand[];\n}\n\ntype Paths = PathProps[];\n\nfunction setupSvgRenderer({\n el,\n paths,\n enableBackdropBlur,\n}: {\n el: SVGSVGElement;\n paths: Paths;\n enableBackdropBlur: boolean | undefined;\n}) {\n // Clear previous content\n while (el.firstChild) {\n el.removeChild(el.firstChild);\n }\n\n // Optionally add backdrop blur filter\n if (enableBackdropBlur) {\n const defs = document.createElementNS(\"http://www.w3.org/2000/svg\", \"defs\");\n const filter = document.createElementNS(\n \"http://www.w3.org/2000/svg\",\n \"filter\",\n );\n filter.setAttribute(\"id\", \"backdrop-blur\");\n filter.innerHTML = `\n <feGaussianBlur stdDeviation=\"8\" result=\"blur\"/>\n <feMerge>\n <feMergeNode in=\"blur\"/>\n <feMergeNode in=\"SourceGraphic\"/>\n </feMerge>\n `;\n defs.appendChild(filter);\n el.appendChild(defs);\n }\n\n // Convert path commands to SVG path string\n const convertPathToString = (pathCommands: [string, string, string][]) => {\n return (\n pathCommands\n .map(([command, x, y]) => {\n // Replace percentage-based coordinates with actual values\n const processCoordinate = (coord: string, isX: boolean) => {\n if (coord.includes(\"%\")) {\n // For demo purposes, we'll use viewport-relative values\n return coord\n .replace(\"100%\", isX ? \"200\" : \"40\")\n .replace(\"0%\", \"0\");\n }\n return coord;\n };\n\n const processedX = processCoordinate(x, true);\n const processedY = processCoordinate(y, false);\n\n return `${command}${processedX},${processedY}`;\n })\n .join(\" \") + \" Z\"\n );\n };\n\n // Render each path\n paths.forEach((pathProps) => {\n if (!pathProps.show) return;\n\n const path = document.createElementNS(\"http://www.w3.org/2000/svg\", \"path\");\n\n // Set the path data\n const pathString = convertPathToString(pathProps.path);\n path.setAttribute(\"d\", pathString);\n\n // Apply styles\n Object.entries(pathProps.style).forEach(([key, value]) => {\n if (key === \"strokeWidth\") {\n path.setAttribute(\"stroke-width\", value);\n } else {\n path.setAttribute(key, value);\n }\n });\n\n if (enableBackdropBlur) {\n path.setAttribute(\"filter\", \"url(#backdrop-blur)\");\n }\n\n el.appendChild(path);\n });\n\n return {\n destroy() {\n while (el.firstChild) {\n el.removeChild(el.firstChild);\n }\n },\n };\n}\n\nfunction Frame({\n className,\n paths,\n enableBackdropBlur,\n ...props\n}: {\n paths: Paths;\n enableBackdropBlur?: boolean;\n} & React.ComponentProps<\"svg\">) {\n const svgRef = useRef<SVGSVGElement | null>(null);\n\n useEffect(() => {\n if (svgRef.current && svgRef.current.parentElement) {\n const instance = setupSvgRenderer({\n el: svgRef.current,\n paths,\n enableBackdropBlur,\n });\n\n return () => instance.destroy();\n }\n }, [paths, enableBackdropBlur]);\n\n return (\n <svg\n {...props}\n className={twMerge([\"absolute inset-0 size-full\", className])}\n xmlns=\"http://www.w3.org/2000/svg\"\n ref={svgRef}\n />\n );\n}\n\nexport { Frame };\n",
25+
"path": "./src/components/nurui/frame.tsx",
26+
"content": "import { useRef, useEffect } from \"react\";\nimport { twMerge } from \"tailwind-merge\";\nimport { type Paths, setupSvgRenderer } from \"@left4code/svg-renderer\";\n\nfunction Frame({\n className,\n paths,\n enableBackdropBlur,\n enableViewBox,\n ...props\n}: {\n paths: Paths;\n enableBackdropBlur?: boolean;\n enableViewBox?: boolean;\n} & React.ComponentProps<\"svg\">) {\n const svgRef = useRef<SVGSVGElement | null>(null);\n\n useEffect(() => {\n if (svgRef.current && svgRef.current.parentElement) {\n const instance = setupSvgRenderer({\n el: svgRef.current,\n paths,\n enableBackdropBlur,\n enableViewBox,\n });\n\n return () => instance.destroy();\n }\n }, [paths, enableViewBox, enableBackdropBlur]);\n\n return (\n <svg\n {...props}\n className={twMerge([\"absolute inset-0 size-full\", className])}\n xmlns=\"http://www.w3.org/2000/svg\"\n ref={svgRef}\n />\n );\n}\n\nexport { Frame };\n",
2727
"type": "registry:component"
2828
}
2929
]

0 commit comments

Comments
 (0)