mirror of
https://github.com/jnsahaj/tweakcn.git
synced 2026-10-30 22:37:13 +08:00
feat: Migrate to rr v7 framework mode
This commit is contained in:
@@ -9,6 +9,7 @@ lerna-debug.log*
|
||||
|
||||
.env
|
||||
|
||||
+.react-router/
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import "react-router";
|
||||
|
||||
declare module "react-router" {
|
||||
interface Register {
|
||||
params: Params;
|
||||
}
|
||||
}
|
||||
|
||||
type Params = {
|
||||
"/": {};
|
||||
"/": {};
|
||||
"/editor/theme": {};
|
||||
"/*": {
|
||||
"*": string;
|
||||
};
|
||||
};
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
declare module "virtual:react-router/server-build" {
|
||||
import { ServerBuild } from "react-router";
|
||||
export const assets: ServerBuild["assets"];
|
||||
export const assetsBuildDirectory: ServerBuild["assetsBuildDirectory"];
|
||||
export const basename: ServerBuild["basename"];
|
||||
export const entry: ServerBuild["entry"];
|
||||
export const future: ServerBuild["future"];
|
||||
export const isSpaMode: ServerBuild["isSpaMode"];
|
||||
export const prerender: ServerBuild["prerender"];
|
||||
export const publicPath: ServerBuild["publicPath"];
|
||||
export const routes: ServerBuild["routes"];
|
||||
export const ssr: ServerBuild["ssr"];
|
||||
export const unstable_getCriticalCss: ServerBuild["unstable_getCriticalCss"];
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// React Router generated types for route:
|
||||
// root.tsx
|
||||
|
||||
import type * as T from "react-router/route-module"
|
||||
|
||||
|
||||
|
||||
type Module = typeof import("../root.js")
|
||||
|
||||
export type Info = {
|
||||
parents: [],
|
||||
id: "root"
|
||||
file: "root.tsx"
|
||||
path: ""
|
||||
params: {} & { [key: string]: string | undefined }
|
||||
module: Module
|
||||
loaderData: T.CreateLoaderData<Module>
|
||||
actionData: T.CreateActionData<Module>
|
||||
}
|
||||
|
||||
export namespace Route {
|
||||
export type LinkDescriptors = T.LinkDescriptors
|
||||
export type LinksFunction = () => LinkDescriptors
|
||||
|
||||
export type MetaArgs = T.CreateMetaArgs<Info>
|
||||
export type MetaDescriptors = T.MetaDescriptors
|
||||
export type MetaFunction = (args: MetaArgs) => MetaDescriptors
|
||||
|
||||
export type HeadersArgs = T.HeadersArgs
|
||||
export type HeadersFunction = (args: HeadersArgs) => Headers | HeadersInit
|
||||
|
||||
export type unstable_MiddlewareFunction = T.CreateServerMiddlewareFunction<Info>
|
||||
export type unstable_ClientMiddlewareFunction = T.CreateClientMiddlewareFunction<Info>
|
||||
export type LoaderArgs = T.CreateServerLoaderArgs<Info>
|
||||
export type ClientLoaderArgs = T.CreateClientLoaderArgs<Info>
|
||||
export type ActionArgs = T.CreateServerActionArgs<Info>
|
||||
export type ClientActionArgs = T.CreateClientActionArgs<Info>
|
||||
|
||||
export type HydrateFallbackProps = T.CreateHydrateFallbackProps<Info>
|
||||
export type ComponentProps = T.CreateComponentProps<Info>
|
||||
export type ErrorBoundaryProps = T.CreateErrorBoundaryProps<Info>
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// React Router generated types for route:
|
||||
// pages/home.tsx
|
||||
|
||||
import type * as T from "react-router/route-module"
|
||||
|
||||
import type { Info as Parent0 } from "../../+types/root.js"
|
||||
|
||||
type Module = typeof import("../home.js")
|
||||
|
||||
export type Info = {
|
||||
parents: [Parent0],
|
||||
id: "pages/home"
|
||||
file: "pages/home.tsx"
|
||||
path: "/"
|
||||
params: {} & { [key: string]: string | undefined }
|
||||
module: Module
|
||||
loaderData: T.CreateLoaderData<Module>
|
||||
actionData: T.CreateActionData<Module>
|
||||
}
|
||||
|
||||
export namespace Route {
|
||||
export type LinkDescriptors = T.LinkDescriptors
|
||||
export type LinksFunction = () => LinkDescriptors
|
||||
|
||||
export type MetaArgs = T.CreateMetaArgs<Info>
|
||||
export type MetaDescriptors = T.MetaDescriptors
|
||||
export type MetaFunction = (args: MetaArgs) => MetaDescriptors
|
||||
|
||||
export type HeadersArgs = T.HeadersArgs
|
||||
export type HeadersFunction = (args: HeadersArgs) => Headers | HeadersInit
|
||||
|
||||
export type unstable_MiddlewareFunction = T.CreateServerMiddlewareFunction<Info>
|
||||
export type unstable_ClientMiddlewareFunction = T.CreateClientMiddlewareFunction<Info>
|
||||
export type LoaderArgs = T.CreateServerLoaderArgs<Info>
|
||||
export type ClientLoaderArgs = T.CreateClientLoaderArgs<Info>
|
||||
export type ActionArgs = T.CreateServerActionArgs<Info>
|
||||
export type ClientActionArgs = T.CreateClientActionArgs<Info>
|
||||
|
||||
export type HydrateFallbackProps = T.CreateHydrateFallbackProps<Info>
|
||||
export type ComponentProps = T.CreateComponentProps<Info>
|
||||
export type ErrorBoundaryProps = T.CreateErrorBoundaryProps<Info>
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// React Router generated types for route:
|
||||
// pages/index.tsx
|
||||
|
||||
import type * as T from "react-router/route-module"
|
||||
|
||||
import type { Info as Parent0 } from "../../+types/root.js"
|
||||
|
||||
type Module = typeof import("../index.js")
|
||||
|
||||
export type Info = {
|
||||
parents: [Parent0],
|
||||
id: "pages/index"
|
||||
file: "pages/index.tsx"
|
||||
path: "/editor/theme"
|
||||
params: {} & { [key: string]: string | undefined }
|
||||
module: Module
|
||||
loaderData: T.CreateLoaderData<Module>
|
||||
actionData: T.CreateActionData<Module>
|
||||
}
|
||||
|
||||
export namespace Route {
|
||||
export type LinkDescriptors = T.LinkDescriptors
|
||||
export type LinksFunction = () => LinkDescriptors
|
||||
|
||||
export type MetaArgs = T.CreateMetaArgs<Info>
|
||||
export type MetaDescriptors = T.MetaDescriptors
|
||||
export type MetaFunction = (args: MetaArgs) => MetaDescriptors
|
||||
|
||||
export type HeadersArgs = T.HeadersArgs
|
||||
export type HeadersFunction = (args: HeadersArgs) => Headers | HeadersInit
|
||||
|
||||
export type unstable_MiddlewareFunction = T.CreateServerMiddlewareFunction<Info>
|
||||
export type unstable_ClientMiddlewareFunction = T.CreateClientMiddlewareFunction<Info>
|
||||
export type LoaderArgs = T.CreateServerLoaderArgs<Info>
|
||||
export type ClientLoaderArgs = T.CreateClientLoaderArgs<Info>
|
||||
export type ActionArgs = T.CreateServerActionArgs<Info>
|
||||
export type ClientActionArgs = T.CreateClientActionArgs<Info>
|
||||
|
||||
export type HydrateFallbackProps = T.CreateHydrateFallbackProps<Info>
|
||||
export type ComponentProps = T.CreateComponentProps<Info>
|
||||
export type ErrorBoundaryProps = T.CreateErrorBoundaryProps<Info>
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// React Router generated types for route:
|
||||
// pages/not-found.tsx
|
||||
|
||||
import type * as T from "react-router/route-module"
|
||||
|
||||
import type { Info as Parent0 } from "../../+types/root.js"
|
||||
|
||||
type Module = typeof import("../not-found.js")
|
||||
|
||||
export type Info = {
|
||||
parents: [Parent0],
|
||||
id: "pages/not-found"
|
||||
file: "pages/not-found.tsx"
|
||||
path: "*"
|
||||
params: {"*": string} & { [key: string]: string | undefined }
|
||||
module: Module
|
||||
loaderData: T.CreateLoaderData<Module>
|
||||
actionData: T.CreateActionData<Module>
|
||||
}
|
||||
|
||||
export namespace Route {
|
||||
export type LinkDescriptors = T.LinkDescriptors
|
||||
export type LinksFunction = () => LinkDescriptors
|
||||
|
||||
export type MetaArgs = T.CreateMetaArgs<Info>
|
||||
export type MetaDescriptors = T.MetaDescriptors
|
||||
export type MetaFunction = (args: MetaArgs) => MetaDescriptors
|
||||
|
||||
export type HeadersArgs = T.HeadersArgs
|
||||
export type HeadersFunction = (args: HeadersArgs) => Headers | HeadersInit
|
||||
|
||||
export type unstable_MiddlewareFunction = T.CreateServerMiddlewareFunction<Info>
|
||||
export type unstable_ClientMiddlewareFunction = T.CreateClientMiddlewareFunction<Info>
|
||||
export type LoaderArgs = T.CreateServerLoaderArgs<Info>
|
||||
export type ClientLoaderArgs = T.CreateClientLoaderArgs<Info>
|
||||
export type ActionArgs = T.CreateServerActionArgs<Info>
|
||||
export type ClientActionArgs = T.CreateClientActionArgs<Info>
|
||||
|
||||
export type HydrateFallbackProps = T.CreateHydrateFallbackProps<Info>
|
||||
export type ComponentProps = T.CreateComponentProps<Info>
|
||||
export type ErrorBoundaryProps = T.CreateErrorBoundaryProps<Info>
|
||||
}
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<!-- Primary Meta Tags -->
|
||||
<title>
|
||||
Beautiful themes for shadcn/ui — tweakcn | Theme Editor & Generator
|
||||
</title>
|
||||
<meta
|
||||
name="title"
|
||||
content="Beautiful themes for shadcn/ui — tweakcn | Theme Editor & Generator"
|
||||
/>
|
||||
<meta
|
||||
name="description"
|
||||
content="tweakcn is a powerful theme editor for shadcn/ui components, offering beautifully designed themes and seamless Tailwind CSS integration. Create, customize, and export themes instantly."
|
||||
/>
|
||||
|
||||
<!-- Canonical URL -->
|
||||
<link rel="canonical" href="https://tweakcn.com/" />
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&family=Fira+Code:wght@300..700&family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=IBM+Plex+Sans:ital,wght@0,100..700;1,100..700&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&family=Lora:ital,wght@0,400..700;1,400..700&family=Merriweather:ital,opsz,wght@0,18..144,300..900;1,18..144,300..900&family=Montserrat:ital,wght@0,100..900;1,100..900&family=Open+Sans:ital,wght@0,300..800;1,300..800&family=Outfit:wght@100..900&family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Plus+Jakarta+Sans:ital,wght@0,200..800;1,200..800&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto:ital,wght@0,100..900;1,100..900&family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&family=Space+Grotesk:wght@300..700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://tweakcn.com/" />
|
||||
<meta
|
||||
property="og:title"
|
||||
content="Beautiful themes for shadcn/ui — tweakcn | Theme Editor & Generator"
|
||||
/>
|
||||
<meta
|
||||
property="og:description"
|
||||
content="tweakcn is a powerful theme editor for shadcn/ui components, offering beautifully designed themes and seamless Tailwind CSS integration. Create, customize, and export themes instantly."
|
||||
/>
|
||||
<meta property="og:image" content="https://tweakcn.com/og-image.png" />
|
||||
<meta property="og:site_name" content="tweakcn" />
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:url" content="https://tweakcn.com/" />
|
||||
<meta
|
||||
property="twitter:title"
|
||||
content="Beautiful themes for shadcn/ui — tweakcn | Theme Editor & Generator"
|
||||
/>
|
||||
<meta
|
||||
property="twitter:description"
|
||||
content="tweakcn is a powerful theme editor for shadcn/ui components, offering beautifully designed themes and seamless Tailwind CSS integration. Create, customize, and export themes instantly."
|
||||
/>
|
||||
<meta property="twitter:image" content="https://tweakcn.com/og-image.png" />
|
||||
|
||||
<!-- Keywords -->
|
||||
<meta
|
||||
name="keywords"
|
||||
content="theme editor, theme generator, shadcn, ui, components, react, tailwind, button, editor, visual editor, component editor, web development, frontend, design system, UI components, React components, Tailwind CSS, shadcn/ui themes"
|
||||
/>
|
||||
|
||||
<!-- Author -->
|
||||
<meta name="author" content="Sahaj Jain" />
|
||||
|
||||
<!-- Theme Color -->
|
||||
<meta name="theme-color" content="#000000" />
|
||||
|
||||
<!-- Additional Meta Tags -->
|
||||
<meta name="robots" content="index, follow" />
|
||||
<meta name="language" content="English" />
|
||||
<meta name="revisit-after" content="7 days" />
|
||||
<meta name="generator" content="Vite" />
|
||||
|
||||
<!-- Structured Data -->
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebApplication",
|
||||
"name": "tweakcn",
|
||||
"description": "A powerful theme editor for shadcn/ui components, offering beautifully designed themes and seamless Tailwind CSS integration.",
|
||||
"url": "https://tweakcn.com",
|
||||
"applicationCategory": "DesignApplication",
|
||||
"operatingSystem": "Web",
|
||||
"offers": {
|
||||
"@type": "Offer",
|
||||
"price": "0",
|
||||
"priceCurrency": "USD"
|
||||
},
|
||||
"author": {
|
||||
"@type": "Person",
|
||||
"name": "Sahaj Jain"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<!-- IMPORTANT: DO NOT REMOVE THIS SCRIPT TAG OR THIS VERY COMMENT! -->
|
||||
<script src="https://cdn.gpteng.co/gptengineer.js" type="module"></script>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
Generated
+810
File diff suppressed because it is too large
Load Diff
+4
-1
@@ -4,7 +4,7 @@
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"dev": "react-router dev",
|
||||
"build": "tsx scripts/generate-theme-registry.ts && vite build",
|
||||
"build:dev": "tsx scripts/generate-theme-registry.ts && vite build --mode development",
|
||||
"lint": "eslint .",
|
||||
@@ -40,6 +40,7 @@
|
||||
"@radix-ui/react-toggle": "^1.1.2",
|
||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@react-router/node": "^7.5.0",
|
||||
"@tanstack/react-query": "^5.56.2",
|
||||
"@tanstack/react-table": "^8.21.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
@@ -49,6 +50,7 @@
|
||||
"date-fns": "^3.6.0",
|
||||
"embla-carousel-react": "^8.3.0",
|
||||
"input-otp": "^1.2.4",
|
||||
"isbot": "^5",
|
||||
"lucide-react": "^0.483.0",
|
||||
"motion": "^12.5.0",
|
||||
"next-themes": "^0.3.0",
|
||||
@@ -73,6 +75,7 @@
|
||||
"@esbuild/darwin-arm64": "^0.25.2",
|
||||
"@eslint/js": "^9.9.0",
|
||||
"@faker-js/faker": "^9.6.0",
|
||||
"@react-router/dev": "^7.5.0",
|
||||
"@tailwindcss/container-queries": "^0.1.1",
|
||||
"@tailwindcss/postcss": "^4.0.15",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { Config } from "@react-router/dev/config";
|
||||
|
||||
export default {
|
||||
appDirectory: "src",
|
||||
ssr: false,
|
||||
} satisfies Config;
|
||||
+5
-19
@@ -2,16 +2,10 @@ import { Toaster } from "@/components/ui/toaster";
|
||||
import { Toaster as Sonner } from "@/components/ui/sonner";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { BrowserRouter, Routes, Route } from "react-router";
|
||||
import Home from "./pages/home";
|
||||
import NotFound from "./pages/not-found";
|
||||
import { Outlet } from "react-router";
|
||||
import { ThemeProvider } from "./components/theme-provider";
|
||||
import { PostHogProvider } from "posthog-js/react";
|
||||
import { HelmetProvider } from "react-helmet-async";
|
||||
import { lazy, Suspense } from "react";
|
||||
import { Loading } from "@/components/loading";
|
||||
|
||||
const Index = lazy(() => import("./pages/index"));
|
||||
import * as Helmet from "react-helmet-async";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
const options = {
|
||||
@@ -19,7 +13,7 @@ const options = {
|
||||
};
|
||||
|
||||
const App = () => (
|
||||
<HelmetProvider>
|
||||
<Helmet.HelmetProvider>
|
||||
<ThemeProvider defaultTheme="light">
|
||||
<PostHogProvider
|
||||
apiKey={import.meta.env.VITE_PUBLIC_POSTHOG_KEY}
|
||||
@@ -29,20 +23,12 @@ const App = () => (
|
||||
<TooltipProvider>
|
||||
<Toaster />
|
||||
<Sonner />
|
||||
<Suspense fallback={<Loading />}>
|
||||
<BrowserRouter>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/editor/theme" element={<Index />} />
|
||||
<Route path="*" element={<NotFound />} />
|
||||
</Routes>
|
||||
</BrowserRouter>
|
||||
</Suspense>
|
||||
<Outlet />
|
||||
</TooltipProvider>
|
||||
</QueryClientProvider>
|
||||
</PostHogProvider>
|
||||
</ThemeProvider>
|
||||
</HelmetProvider>
|
||||
</Helmet.HelmetProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import { HydratedRouter } from "react-router/dom";
|
||||
import "./index.css";
|
||||
|
||||
ReactDOM.hydrateRoot(
|
||||
document,
|
||||
<React.StrictMode>
|
||||
<HydratedRouter />
|
||||
</React.StrictMode>
|
||||
);
|
||||
@@ -1,5 +0,0 @@
|
||||
import { createRoot } from "react-dom/client";
|
||||
import App from "./app.tsx";
|
||||
import "./index.css";
|
||||
|
||||
createRoot(document.getElementById("root")!).render(<App />);
|
||||
+1
-1
@@ -9,7 +9,7 @@ import { FAQ } from "@/components/home/faq";
|
||||
import { CTA } from "@/components/home/cta";
|
||||
import { Footer } from "@/components/home/footer";
|
||||
|
||||
export default function HomePage() {
|
||||
export default function Component() {
|
||||
const [isScrolled, setIsScrolled] = useState(false);
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
|
||||
|
||||
+2
-4
@@ -11,7 +11,7 @@ import { Helmet } from "react-helmet-async";
|
||||
import { useGithubStars } from "@/hooks/use-github-stars";
|
||||
import BuyMeACoffeeIcon from "@/assets/buymeacoffee.svg?react";
|
||||
|
||||
const Index = () => {
|
||||
export default function Component() {
|
||||
const { editorType = "theme" } = useParams();
|
||||
const editorConfig = getEditorConfig(editorType);
|
||||
const { theme, toggleTheme } = useTheme();
|
||||
@@ -81,6 +81,4 @@ const Index = () => {
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Index;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { useLocation } from "react-router";
|
||||
import { useEffect } from "react";
|
||||
|
||||
const NotFound = () => {
|
||||
export default function Component() {
|
||||
const location = useLocation();
|
||||
|
||||
useEffect(() => {
|
||||
console.error(
|
||||
"404 Error: User attempted to access non-existent route:",
|
||||
location.pathname,
|
||||
location.pathname
|
||||
);
|
||||
}, [location.pathname]);
|
||||
|
||||
@@ -22,6 +22,4 @@ const NotFound = () => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotFound;
|
||||
}
|
||||
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router";
|
||||
import App from "./app"; // Import the main App component
|
||||
|
||||
export function Layout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charSet="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
{/* Primary Meta Tags */}
|
||||
<title>
|
||||
Beautiful themes for shadcn/ui — tweakcn | Theme Editor & Generator
|
||||
</title>
|
||||
<meta
|
||||
name="title"
|
||||
content="Beautiful themes for shadcn/ui — tweakcn | Theme Editor & Generator"
|
||||
/>
|
||||
<meta
|
||||
name="description"
|
||||
content="tweakcn is a powerful theme editor for shadcn/ui components, offering beautifully designed themes and seamless Tailwind CSS integration. Create, customize, and export themes instantly."
|
||||
/>
|
||||
|
||||
{/* Canonical URL */}
|
||||
<link rel="canonical" href="https://tweakcn.com/" />
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/site.webmanifest" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link
|
||||
rel="preconnect"
|
||||
href="https://fonts.gstatic.com"
|
||||
crossOrigin="anonymous"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&family=Fira+Code:wght@300..700&family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=IBM+Plex+Sans:ital,wght@0,100..700;1,100..700&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&family=Libre+Baskerville:ital,wght@0,400;0,700;1,400&family=Lora:ital,wght@0,400..700;1,400..700&family=Merriweather:ital,opsz,wght@0,18..144,300..900;1,18..144,300..900&family=Montserrat:ital,wght@0,100..900;1,100..900&family=Open+Sans:ital,wght@0,300..800;1,300..800&family=Outfit:wght@100..900&family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Plus+Jakarta+Sans:ital,wght@0,200..800;1,200..800&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto:ital,wght@0,100..900;1,100..900&family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&family=Source+Serif+4:ital,opsz,wght@0,8..60,200..900;1,8..60,200..900&family=Space+Grotesk:wght@300..700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
{/* Open Graph / Facebook */}
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://tweakcn.com/" />
|
||||
<meta
|
||||
property="og:title"
|
||||
content="Beautiful themes for shadcn/ui — tweakcn | Theme Editor & Generator"
|
||||
/>
|
||||
<meta
|
||||
property="og:description"
|
||||
content="tweakcn is a powerful theme editor for shadcn/ui components, offering beautifully designed themes and seamless Tailwind CSS integration. Create, customize, and export themes instantly."
|
||||
/>
|
||||
<meta property="og:image" content="https://tweakcn.com/og-image.png" />
|
||||
<meta property="og:site_name" content="tweakcn" />
|
||||
|
||||
{/* Twitter */}
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:url" content="https://tweakcn.com/" />
|
||||
<meta
|
||||
property="twitter:title"
|
||||
content="Beautiful themes for shadcn/ui — tweakcn | Theme Editor & Generator"
|
||||
/>
|
||||
<meta
|
||||
property="twitter:description"
|
||||
content="tweakcn is a powerful theme editor for shadcn/ui components, offering beautifully designed themes and seamless Tailwind CSS integration. Create, customize, and export themes instantly."
|
||||
/>
|
||||
<meta property="twitter:image" content="https://tweakcn.com/og-image.png" />
|
||||
|
||||
{/* Keywords */}
|
||||
<meta
|
||||
name="keywords"
|
||||
content="theme editor, theme generator, shadcn, ui, components, react, tailwind, button, editor, visual editor, component editor, web development, frontend, design system, UI components, React components, Tailwind CSS, shadcn/ui themes"
|
||||
/>
|
||||
|
||||
{/* Author */}
|
||||
<meta name="author" content="Sahaj Jain" />
|
||||
|
||||
{/* Theme Color */}
|
||||
<meta name="theme-color" content="#000000" />
|
||||
|
||||
{/* Additional Meta Tags */}
|
||||
<meta name="robots" content="index, follow" />
|
||||
<meta name="language" content="English" />
|
||||
<meta name="revisit-after" content="7 days" />
|
||||
<meta name="generator" content="Vite" />
|
||||
|
||||
{/* Structured Data */}
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: JSON.stringify({
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebApplication",
|
||||
name: "tweakcn",
|
||||
description:
|
||||
"A powerful theme editor for shadcn/ui components, offering beautifully designed themes and seamless Tailwind CSS integration.",
|
||||
url: "https://tweakcn.com",
|
||||
applicationCategory: "DesignApplication",
|
||||
operatingSystem: "Web",
|
||||
offers: {
|
||||
"@type": "Offer",
|
||||
price: "0",
|
||||
priceCurrency: "USD",
|
||||
},
|
||||
author: {
|
||||
"@type": "Person",
|
||||
name: "Sahaj Jain",
|
||||
},
|
||||
}),
|
||||
}}
|
||||
/>
|
||||
<Meta />
|
||||
<Links />
|
||||
</head>
|
||||
<body>
|
||||
{children}
|
||||
<ScrollRestoration />
|
||||
<Scripts />
|
||||
{/* IMPORTANT: DO NOT REMOVE THIS SCRIPT TAG OR THIS VERY COMMENT! */}
|
||||
<script src="https://cdn.gpteng.co/gptengineer.js" type="module"></script>
|
||||
{/* <script type="module" src="/src/main.tsx"></script> - This is now handled by Scripts */}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Root() {
|
||||
return <App />;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { type RouteConfig, route } from "@react-router/dev/routes";
|
||||
|
||||
export default [
|
||||
route("/", "pages/home.tsx"),
|
||||
route("/editor/theme", "pages/index.tsx"),
|
||||
route("*", "pages/not-found.tsx"), // Wildcard for not found pages
|
||||
] satisfies RouteConfig;
|
||||
@@ -1,7 +1,7 @@
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
import { ThemeEditorState, EditorType } from "@/types/editor";
|
||||
import { isEqual } from "lodash";
|
||||
import * as _ from "lodash";
|
||||
import { defaultThemeState } from "@/config/theme";
|
||||
import { getPresetThemeStyles } from "../utils/theme-presets";
|
||||
|
||||
@@ -39,7 +39,7 @@ export const useEditorStore = create<EditorStore>()(
|
||||
hasStateChanged: (type: EditorType) => {
|
||||
const state = get();
|
||||
if (type === "theme") {
|
||||
return !isEqual(state.themeState.styles, defaultThemeState.styles);
|
||||
return !_.isEqual(state.themeState.styles, defaultThemeState.styles);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react-swc";
|
||||
import { reactRouter } from "@react-router/dev/vite";
|
||||
import path from "path";
|
||||
import { componentTagger } from "lovable-tagger";
|
||||
import svgr from "vite-plugin-svgr";
|
||||
@@ -12,7 +12,7 @@ export default defineConfig(({ mode }) => ({
|
||||
port: 8080,
|
||||
},
|
||||
plugins: [
|
||||
react(),
|
||||
reactRouter(),
|
||||
svgr(),
|
||||
tailwindcss(),
|
||||
mode === "development" && componentTagger(),
|
||||
|
||||
Reference in New Issue
Block a user