mirror of
https://github.com/jnsahaj/tweakcn.git
synced 2026-09-01 15:37:45 +08:00
feat: Prerendering
This commit is contained in:
Generated
-8581
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -13,6 +13,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^3.9.0",
|
||||
"@ngard/tiny-isequal": "^1.1.0",
|
||||
"@radix-ui/react-accordion": "^1.2.3",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.6",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.2",
|
||||
@@ -58,7 +59,6 @@
|
||||
"react": "^18.3.1",
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-helmet-async": "^2.0.5",
|
||||
"react-hook-form": "^7.53.0",
|
||||
"react-resizable-panels": "^2.1.3",
|
||||
"react-router": "^7.5.0",
|
||||
|
||||
Generated
+6428
File diff suppressed because it is too large
Load Diff
+14
-17
@@ -5,7 +5,6 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { Outlet } from "react-router";
|
||||
import { ThemeProvider } from "./components/theme-provider";
|
||||
import { PostHogProvider } from "posthog-js/react";
|
||||
import * as Helmet from "react-helmet-async";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
const options = {
|
||||
@@ -13,22 +12,20 @@ const options = {
|
||||
};
|
||||
|
||||
const App = () => (
|
||||
<Helmet.HelmetProvider>
|
||||
<ThemeProvider defaultTheme="light">
|
||||
<PostHogProvider
|
||||
apiKey={import.meta.env.VITE_PUBLIC_POSTHOG_KEY}
|
||||
options={options}
|
||||
>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<TooltipProvider>
|
||||
<Toaster />
|
||||
<Sonner />
|
||||
<Outlet />
|
||||
</TooltipProvider>
|
||||
</QueryClientProvider>
|
||||
</PostHogProvider>
|
||||
</ThemeProvider>
|
||||
</Helmet.HelmetProvider>
|
||||
<ThemeProvider defaultTheme="light">
|
||||
<PostHogProvider
|
||||
apiKey={import.meta.env.VITE_PUBLIC_POSTHOG_KEY}
|
||||
options={options}
|
||||
>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<TooltipProvider>
|
||||
<Toaster />
|
||||
<Sonner />
|
||||
<Outlet />
|
||||
</TooltipProvider>
|
||||
</QueryClientProvider>
|
||||
</PostHogProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
||||
@@ -9,6 +9,18 @@ import { FAQ } from "@/components/home/faq";
|
||||
import { CTA } from "@/components/home/cta";
|
||||
import { Footer } from "@/components/home/footer";
|
||||
|
||||
export function meta() {
|
||||
return [
|
||||
{
|
||||
title: "Beautiful themes for shadcn/ui — tweakcn | Theme Editor & Generator",
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
content: "Beautiful themes for shadcn/ui — tweakcn | Theme Editor & Generator",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export default function Component() {
|
||||
const [isScrolled, setIsScrolled] = useState(false);
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
|
||||
+87
-12
@@ -1,19 +1,101 @@
|
||||
import { getEditorConfig } from "@/config/editors";
|
||||
import Editor from "@/components/editor/editor";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Link, useParams } from "react-router";
|
||||
import { Link } from "react-router";
|
||||
import { Moon, Sun } from "lucide-react";
|
||||
import GitHubIcon from "@/assets/github.svg?react";
|
||||
import { cn } from "../lib/utils";
|
||||
import { useTheme } from "../components/theme-provider";
|
||||
import logo from "@/assets/logo.png";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useGithubStars } from "@/hooks/use-github-stars";
|
||||
import BuyMeACoffeeIcon from "@/assets/buymeacoffee.svg?react";
|
||||
|
||||
export function meta() {
|
||||
const siteName = "tweakcn";
|
||||
const siteUrl = "https://tweakcn.com/";
|
||||
const ogImage = "https://tweakcn.com/og-image.png";
|
||||
const shortTitle = "Theme Editor for shadcn/ui — tweakcn";
|
||||
const longTitle =
|
||||
"Beautiful themes for shadcn/ui — tweakcn | Theme Editor & Generator";
|
||||
const shortDescription =
|
||||
"Customize theme for shadcn/ui with tweakcn's interactive editor. Supports Tailwind CSS v4, Shadcn UI, and custom styles. Modify properties, preview changes, and get the code in real time.";
|
||||
const longDescription =
|
||||
"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.";
|
||||
|
||||
return [
|
||||
{ title: shortTitle },
|
||||
{ name: "description", content: shortDescription },
|
||||
{
|
||||
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",
|
||||
},
|
||||
{ name: "author", content: "Sahaj Jain" },
|
||||
{ name: "image", content: ogImage },
|
||||
{ name: "url", content: siteUrl },
|
||||
{ name: "twitter:card", content: "summary_large_image" },
|
||||
{ name: "twitter:url", content: siteUrl },
|
||||
{ name: "twitter:title", content: longTitle },
|
||||
{ name: "twitter:description", content: longDescription },
|
||||
{ name: "twitter:image", content: ogImage },
|
||||
{ name: "robots", content: "index, follow" },
|
||||
{ name: "language", content: "English" },
|
||||
{ name: "revisit-after", content: "7 days" },
|
||||
{ name: "generator", content: "Vite" },
|
||||
{ name: "charset", content: "UTF-8" },
|
||||
{ name: "viewport", content: "width=device-width, initial-scale=1.0" },
|
||||
{ property: "og:type", content: "website" },
|
||||
{ property: "og:url", content: siteUrl },
|
||||
{ property: "og:title", content: longTitle },
|
||||
{ property: "og:description", content: longDescription },
|
||||
{ property: "og:image", content: ogImage },
|
||||
{ property: "og:site_name", content: siteName },
|
||||
];
|
||||
}
|
||||
|
||||
export function links() {
|
||||
return [
|
||||
{
|
||||
rel: "canonical",
|
||||
href: "https://tweakcn.com/",
|
||||
},
|
||||
{
|
||||
rel: "apple-touch-icon",
|
||||
href: "/apple-touch-icon.png",
|
||||
},
|
||||
{
|
||||
rel: "icon",
|
||||
type: "image/png",
|
||||
sizes: "32x32",
|
||||
href: "/favicon-32x32.png",
|
||||
},
|
||||
{
|
||||
rel: "icon",
|
||||
type: "image/png",
|
||||
sizes: "16x16",
|
||||
href: "/favicon-16x16.png",
|
||||
},
|
||||
{
|
||||
rel: "manifest",
|
||||
href: "/site.webmanifest",
|
||||
},
|
||||
{
|
||||
rel: "preconnect",
|
||||
href: "https://fonts.googleapis.com",
|
||||
},
|
||||
{
|
||||
rel: "preconnect",
|
||||
href: "https://fonts.gstatic.com",
|
||||
crossOrigin: "anonymous",
|
||||
},
|
||||
{
|
||||
rel: "stylesheet",
|
||||
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",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export default function Component() {
|
||||
const { editorType = "theme" } = useParams();
|
||||
const editorConfig = getEditorConfig(editorType);
|
||||
const { theme, toggleTheme } = useTheme();
|
||||
const { stargazersCount } = useGithubStars("jnsahaj", "tweakcn");
|
||||
|
||||
@@ -23,13 +105,6 @@ export default function Component() {
|
||||
"h-screen flex flex-col text-foreground bg-background transition-colors"
|
||||
)}
|
||||
>
|
||||
<Helmet>
|
||||
<title>{`${editorConfig.name} Editor for shadcn/ui — tweakcn`}</title>
|
||||
<meta
|
||||
name="description"
|
||||
content={`Customize ${editorConfig.name} for shadcn/ui with tweakcn's interactive editor. Supports Tailwind CSS v4, Shadcn UI, and custom styles. Modify properties, preview changes, and get the code in real time.`}
|
||||
/>
|
||||
</Helmet>
|
||||
<header className="border-b">
|
||||
<div className="px-2 md:px-4 py-4 flex items-center gap-2 justify-between">
|
||||
<div className="flex items-center gap-1">
|
||||
@@ -77,7 +152,7 @@ export default function Component() {
|
||||
</header>
|
||||
|
||||
<main className="flex-1 overflow-hidden">
|
||||
<Editor config={editorConfig} />
|
||||
<Editor config={getEditorConfig("theme")} />
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
|
||||
+1
-82
@@ -1,91 +1,10 @@
|
||||
import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router";
|
||||
import { Links, Meta, 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={{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
import { ThemeEditorState, EditorType } from "@/types/editor";
|
||||
import * as _ from "lodash";
|
||||
import { isEqual } from "@ngard/tiny-isequal";
|
||||
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;
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user