diff --git a/apps/web/src/features/brand-studio/components/brand-studio-panel.tsx b/apps/web/src/features/brand-studio/components/brand-studio-panel.tsx index 760150d..0db6860 100644 --- a/apps/web/src/features/brand-studio/components/brand-studio-panel.tsx +++ b/apps/web/src/features/brand-studio/components/brand-studio-panel.tsx @@ -5,7 +5,6 @@ import { RbcButton } from "@/components/ui/rbc-button"; import { exportBrandJson } from "@/features/brand-studio/exporters/export-brand-json"; import { useBrandStore } from "@/features/brand-studio/store/brand-store"; import { downloadFile } from "@/features/theme-engine/exporters/download-file"; -import { LogoBuilderPanel } from "@/features/logo-builder/components/logo-builder-panel"; export function BrandStudioPanel() { const brand = useBrandStore((state) => state.brand); @@ -182,10 +181,8 @@ export function BrandStudioPanel() { - Export Brand Kit JSON - - - + Export Brand Kit JSON + ); diff --git a/apps/web/src/features/logo-builder/components/logo-builder-panel.tsx b/apps/web/src/features/logo-builder/components/logo-builder-panel.tsx deleted file mode 100644 index 08bde40..0000000 --- a/apps/web/src/features/logo-builder/components/logo-builder-panel.tsx +++ /dev/null @@ -1,59 +0,0 @@ -"use client"; - -import { RbcBadge } from "@/components/ui/rbc-badge"; -import { RbcButton } from "@/components/ui/rbc-button"; -import { exportLogoSvg } from "@/features/logo-builder/exporters/export-logo-svg"; -import { LogoControls } from "@/features/logo-builder/components/logo-controls"; -import { LogoPreview } from "@/features/logo-builder/components/logo-preview"; -import { useLogoStore } from "@/features/logo-builder/store/logo-store"; -import { downloadFile } from "@/features/theme-engine/exporters/download-file"; - -export function LogoBuilderPanel() { - const logo = useLogoStore((state) => state.logo); - const resetLogo = useLogoStore((state) => state.resetLogo); - - function handleExportSvg(): void { - downloadFile("rainbowcode-logo.svg", exportLogoSvg(logo), "image/svg+xml"); - } - - return ( -
-
-
- -
-
-
- Logo Builder - SVG Export -
- -

- Visual logo system -

- -

- Create a text-based brand mark with typography, gradient, preview, - and exportable SVG. -

-
- - - Reset - -
-
- -
- - -
- - - Export Logo SVG - -
-
-
- ); -} \ No newline at end of file diff --git a/apps/web/src/features/logo-builder/components/logo-controls.tsx b/apps/web/src/features/logo-builder/components/logo-controls.tsx deleted file mode 100644 index 80423b8..0000000 --- a/apps/web/src/features/logo-builder/components/logo-controls.tsx +++ /dev/null @@ -1,248 +0,0 @@ -"use client"; - -import type { - LogoFontFamily, - LogoGradientDirection, -} from "@/features/logo-builder/types/logo"; -import { useLogoStore } from "@/features/logo-builder/store/logo-store"; - -const fontFamilies: readonly LogoFontFamily[] = [ - "Inter", - "Poppins", - "Montserrat", - "Playfair Display", - "Space Grotesk", -]; - -const gradientDirections: readonly { - readonly label: string; - readonly value: LogoGradientDirection; -}[] = [ - { label: "Right", value: "to-right" }, - { label: "Bottom Right", value: "to-bottom-right" }, - { label: "Bottom", value: "to-bottom" }, - { label: "Top Right", value: "to-top-right" }, -]; - -function fieldClass(): string { - return "mt-1 h-11 w-full rounded-2xl border border-slate-200 bg-white px-3 text-sm font-semibold text-slate-950 outline-none transition focus:border-indigo-300 focus:ring-4 focus:ring-indigo-500/10 dark:border-slate-800 dark:bg-slate-950 dark:text-white"; -} - -export function LogoControls() { - const logo = useLogoStore((state) => state.logo); - const updateText = useLogoStore((state) => state.updateText); - const updateTagline = useLogoStore((state) => state.updateTagline); - const updateFontFamily = useLogoStore((state) => state.updateFontFamily); - const updateFontWeight = useLogoStore((state) => state.updateFontWeight); - const updateLetterSpacing = useLogoStore( - (state) => state.updateLetterSpacing, - ); - const updatePrimaryColor = useLogoStore((state) => state.updatePrimaryColor); - const updateSecondaryColor = useLogoStore( - (state) => state.updateSecondaryColor, - ); - const updateBackgroundColor = useLogoStore( - (state) => state.updateBackgroundColor, - ); - const updateGradientDirection = useLogoStore( - (state) => state.updateGradientDirection, - ); - const updateRadius = useLogoStore((state) => state.updateRadius); - - return ( -
-
- - updateText(event.currentTarget.value)} - className={fieldClass()} - /> -
- -
- - updateTagline(event.currentTarget.value)} - className={fieldClass()} - /> -
- -
- - -
- -
-
- - - updateFontWeight(Number(event.currentTarget.value)) - } - className={fieldClass()} - /> -
- -
- - - updateLetterSpacing(Number(event.currentTarget.value)) - } - className={fieldClass()} - /> -
-
- -
- - -
- -
- {[ - { - id: "logo-primary-color", - label: "Primary", - value: logo.primaryColor, - onChange: updatePrimaryColor, - }, - { - id: "logo-secondary-color", - label: "Secondary", - value: logo.secondaryColor, - onChange: updateSecondaryColor, - }, - { - id: "logo-background-color", - label: "Background", - value: logo.backgroundColor, - onChange: updateBackgroundColor, - }, - ].map((field) => ( -
- - -
- field.onChange(event.currentTarget.value)} - className="size-11 cursor-pointer rounded-2xl border border-slate-200 bg-white p-1 dark:border-slate-800 dark:bg-slate-950" - /> - field.onChange(event.currentTarget.value)} - className={fieldClass()} - /> -
-
- ))} -
- -
- - updateRadius(Number(event.currentTarget.value))} - className="mt-3 w-full accent-indigo-600" - /> -
-
- ); -} \ No newline at end of file diff --git a/apps/web/src/features/logo-builder/components/logo-preview.tsx b/apps/web/src/features/logo-builder/components/logo-preview.tsx deleted file mode 100644 index 25b4898..0000000 --- a/apps/web/src/features/logo-builder/components/logo-preview.tsx +++ /dev/null @@ -1,88 +0,0 @@ -"use client"; - -import type { LogoConfig } from "@/features/logo-builder/types/logo"; - -function getGradientClass(direction: LogoConfig["gradientDirection"]): string { - if (direction === "to-right") { - return "bg-gradient-to-r"; - } - - if (direction === "to-bottom") { - return "bg-gradient-to-b"; - } - - if (direction === "to-top-right") { - return "bg-gradient-to-tr"; - } - - return "bg-gradient-to-br"; -} - -type LogoPreviewProps = { - readonly logo: LogoConfig; -}; - -export function LogoPreview({ logo }: LogoPreviewProps) { - const initials = (logo.text.trim() || "RBC").slice(0, 3).toUpperCase(); - - return ( -
-
-
-
- -
-
- {initials} -
- -
-

- {logo.text || "Logo"} -

- -

- {logo.tagline} -

-
-
-
-
- ); -} \ No newline at end of file diff --git a/apps/web/src/features/logo-builder/exporters/export-logo-svg.ts b/apps/web/src/features/logo-builder/exporters/export-logo-svg.ts deleted file mode 100644 index cd31a98..0000000 --- a/apps/web/src/features/logo-builder/exporters/export-logo-svg.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { LogoConfig } from "@/features/logo-builder/types/logo"; - -function escapeSvgText(value: string): string { - return value - .replaceAll("&", "&") - .replaceAll("<", "<") - .replaceAll(">", ">") - .replaceAll('"', """) - .replaceAll("'", "'"); -} - -function getGradientCoordinates(direction: LogoConfig["gradientDirection"]): { - readonly x1: string; - readonly y1: string; - readonly x2: string; - readonly y2: string; -} { - if (direction === "to-right") { - return { x1: "0%", y1: "50%", x2: "100%", y2: "50%" }; - } - - if (direction === "to-bottom") { - return { x1: "50%", y1: "0%", x2: "50%", y2: "100%" }; - } - - if (direction === "to-top-right") { - return { x1: "0%", y1: "100%", x2: "100%", y2: "0%" }; - } - - return { x1: "0%", y1: "0%", x2: "100%", y2: "100%" }; -} - -export function exportLogoSvg(logo: LogoConfig): string { - const gradient = getGradientCoordinates(logo.gradientDirection); - const safeText = escapeSvgText(logo.text.trim() || "Logo"); - const safeTagline = escapeSvgText(logo.tagline.trim()); - - return ` - - - - - - - - - ${safeText.slice(0, 3).toUpperCase()} - ${safeText} - ${safeTagline} -`; -} \ No newline at end of file diff --git a/apps/web/src/features/logo-builder/store/logo-store.ts b/apps/web/src/features/logo-builder/store/logo-store.ts deleted file mode 100644 index 928ff76..0000000 --- a/apps/web/src/features/logo-builder/store/logo-store.ts +++ /dev/null @@ -1,138 +0,0 @@ -"use client"; - -import { create } from "zustand"; -import type { - LogoConfig, - LogoFontFamily, - LogoGradientDirection, -} from "@/features/logo-builder/types/logo"; - -export const defaultLogoConfig: LogoConfig = { - text: "RainbowCode", - tagline: "Design visually. Ship clean code.", - fontFamily: "Inter", - fontWeight: 800, - letterSpacing: -2, - primaryColor: "#4f46e5", - secondaryColor: "#db2777", - backgroundColor: "#020617", - gradientDirection: "to-bottom-right", - radius: 32, -}; - -type LogoStoreState = { - readonly logo: LogoConfig; - readonly updateText: (text: string) => void; - readonly updateTagline: (tagline: string) => void; - readonly updateFontFamily: (fontFamily: LogoFontFamily) => void; - readonly updateFontWeight: (fontWeight: number) => void; - readonly updateLetterSpacing: (letterSpacing: number) => void; - readonly updatePrimaryColor: (primaryColor: string) => void; - readonly updateSecondaryColor: (secondaryColor: string) => void; - readonly updateBackgroundColor: (backgroundColor: string) => void; - readonly updateGradientDirection: ( - gradientDirection: LogoGradientDirection, - ) => void; - readonly updateRadius: (radius: number) => void; - readonly resetLogo: () => void; -}; - -export const useLogoStore = create((set) => ({ - logo: defaultLogoConfig, - - updateText: (text) => { - set((state) => ({ - logo: { - ...state.logo, - text, - }, - })); - }, - - updateTagline: (tagline) => { - set((state) => ({ - logo: { - ...state.logo, - tagline, - }, - })); - }, - - updateFontFamily: (fontFamily) => { - set((state) => ({ - logo: { - ...state.logo, - fontFamily, - }, - })); - }, - - updateFontWeight: (fontWeight) => { - set((state) => ({ - logo: { - ...state.logo, - fontWeight, - }, - })); - }, - - updateLetterSpacing: (letterSpacing) => { - set((state) => ({ - logo: { - ...state.logo, - letterSpacing, - }, - })); - }, - - updatePrimaryColor: (primaryColor) => { - set((state) => ({ - logo: { - ...state.logo, - primaryColor, - }, - })); - }, - - updateSecondaryColor: (secondaryColor) => { - set((state) => ({ - logo: { - ...state.logo, - secondaryColor, - }, - })); - }, - - updateBackgroundColor: (backgroundColor) => { - set((state) => ({ - logo: { - ...state.logo, - backgroundColor, - }, - })); - }, - - updateGradientDirection: (gradientDirection) => { - set((state) => ({ - logo: { - ...state.logo, - gradientDirection, - }, - })); - }, - - updateRadius: (radius) => { - set((state) => ({ - logo: { - ...state.logo, - radius, - }, - })); - }, - - resetLogo: () => { - set({ - logo: defaultLogoConfig, - }); - }, -})); \ No newline at end of file diff --git a/apps/web/src/features/logo-builder/tests/export-logo-svg.test.ts b/apps/web/src/features/logo-builder/tests/export-logo-svg.test.ts deleted file mode 100644 index 130b493..0000000 --- a/apps/web/src/features/logo-builder/tests/export-logo-svg.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { exportLogoSvg } from "@/features/logo-builder/exporters/export-logo-svg"; -import { defaultLogoConfig } from "@/features/logo-builder/store/logo-store"; - -describe("exportLogoSvg", () => { - it("exports a valid svg string", () => { - const svg = exportLogoSvg(defaultLogoConfig); - - expect(svg).toContain(""); - expect(svg).toContain("RainbowCode"); - expect(svg).toContain("linearGradient"); - }); - - it("escapes unsafe text", () => { - const svg = exportLogoSvg({ - ...defaultLogoConfig, - text: "