Merge pull request #9 from luisacevelad/feat/theme-system
feat: add theme system with swappable palettes and rebrand to NeuralCut
This commit is contained in:
commit
d65435554f
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "@opencut/web",
|
||||
"name": "@neuralcut/web",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"packageManager": "bun@1.2.18",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "OpenCut",
|
||||
"name": "NeuralCut",
|
||||
"description": "A simple but powerful video editor that gets the job done. In your browser.",
|
||||
"display": "standalone",
|
||||
"start_url": "/",
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ import { getPosts } from "@/lib/blog/query";
|
|||
import type { Post } from "@/lib/blog/types";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Blog - OpenCut",
|
||||
title: "Blog - NeuralCut",
|
||||
description:
|
||||
"Read the latest news and updates about OpenCut, the free and open-source video editor.",
|
||||
"Read the latest news and updates about NeuralCut, the free and open-source video editor.",
|
||||
openGraph: {
|
||||
title: "Blog - OpenCut",
|
||||
title: "Blog - NeuralCut",
|
||||
description:
|
||||
"Read the latest news and updates about OpenCut, the free and open-source video editor.",
|
||||
"Read the latest news and updates about NeuralCut, the free and open-source video editor.",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
|
@ -24,7 +24,7 @@ export default async function BlogPage() {
|
|||
return (
|
||||
<BasePage
|
||||
title="Blog"
|
||||
description="Read the latest news and updates about OpenCut, the free and open-source video editor."
|
||||
description="Read the latest news and updates about NeuralCut, the free and open-source video editor."
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
{data.posts.map((post) => (
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ const ASSET_SECTIONS: AssetSection[] = [
|
|||
{
|
||||
title: "Symbol",
|
||||
description:
|
||||
"Use the symbol on its own when the OpenCut name is already present nearby or space is limited.",
|
||||
"Use the symbol on its own when the NeuralCut name is already present nearby or space is limited.",
|
||||
cols: "2",
|
||||
assets: [
|
||||
{
|
||||
|
|
@ -112,7 +112,7 @@ export default function BrandPage() {
|
|||
title="Brand"
|
||||
description={
|
||||
<>
|
||||
Download OpenCut brand assets for use in your projects.{" "}
|
||||
Download NeuralCut brand assets for use in your projects.{" "}
|
||||
<Link
|
||||
href="#guidelines"
|
||||
className="underline underline-offset-4"
|
||||
|
|
@ -173,10 +173,10 @@ export default function BrandPage() {
|
|||
<div className="flex flex-col gap-3">
|
||||
<h2 className="font-semibold text-lg">Usage</h2>
|
||||
<p className="text-muted-foreground text-base leading-relaxed">
|
||||
OpenCut is open source — the code is free to use under its license.
|
||||
NeuralCut is open source — the code is free to use under its license.
|
||||
That license does not cover the name or logo. You can say you use
|
||||
OpenCut, that your project integrates with OpenCut, or that it was
|
||||
built on top of OpenCut. You cannot name your product OpenCut, imply
|
||||
NeuralCut, that your project integrates with NeuralCut, or that it was
|
||||
built on top of NeuralCut. You cannot name your product NeuralCut, imply
|
||||
we made or endorse your product, or use the marks commercially
|
||||
without asking first. For anything unclear, reach out at{" "}
|
||||
<Link
|
||||
|
|
@ -193,8 +193,8 @@ export default function BrandPage() {
|
|||
<h2 className="font-semibold text-lg">What's not allowed</h2>
|
||||
<ul className="text-muted-foreground text-base flex flex-col gap-2 leading-relaxed">
|
||||
{[
|
||||
"Using OpenCut in the name of your product, service, or domain.",
|
||||
"Implying that OpenCut made, sponsors, or endorses your work.",
|
||||
"Using NeuralCut in the name of your product, service, or domain.",
|
||||
"Implying that NeuralCut made, sponsors, or endorses your work.",
|
||||
"Using the logo or name on merchandise or commercial marketing.",
|
||||
"Modifying the marks.",
|
||||
].map((item) => (
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
|||
const release = getReleaseByVersion({ version });
|
||||
if (!release) return {};
|
||||
return {
|
||||
title: `${release.title} (${release.version}) - OpenCut Changelog`,
|
||||
title: `${release.title} (${release.version}) - NeuralCut Changelog`,
|
||||
description: release.description,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,25 +14,25 @@ import {
|
|||
} from "@/lib/changelog/components/release";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Changelog - OpenCut",
|
||||
description: "What's new in OpenCut",
|
||||
title: "Changelog - NeuralCut",
|
||||
description: "What's new in NeuralCut",
|
||||
openGraph: {
|
||||
title: "Changelog - OpenCut",
|
||||
description: "Every update, improvement, and fix to OpenCut — documented.",
|
||||
title: "Changelog - NeuralCut",
|
||||
description: "Every update, improvement, and fix to NeuralCut — documented.",
|
||||
type: "website",
|
||||
images: [
|
||||
{
|
||||
url: "/open-graph/changlog.jpg",
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: "OpenCut Changelog",
|
||||
alt: "NeuralCut Changelog",
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: "Changelog - OpenCut",
|
||||
description: "What's new in OpenCut",
|
||||
title: "Changelog - NeuralCut",
|
||||
description: "What's new in NeuralCut",
|
||||
images: ["/open-graph/changlog.jpg"],
|
||||
},
|
||||
};
|
||||
|
|
@ -41,7 +41,7 @@ export default function ChangelogPage() {
|
|||
const releases = getSortedReleases();
|
||||
|
||||
return (
|
||||
<BasePage title="Changelog" description="See what's new in OpenCut">
|
||||
<BasePage title="Changelog" description="See what's new in NeuralCut">
|
||||
<div className="mx-auto w-full max-w-3xl">
|
||||
<div className="relative">
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ import { EXTERNAL_TOOLS } from "@/lib/site/external-tools";
|
|||
import { BasePage } from "../base-page";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Contributors - OpenCut",
|
||||
title: "Contributors - NeuralCut",
|
||||
description:
|
||||
"Meet the amazing people who contribute to OpenCut, the free and open-source video editor.",
|
||||
"Meet the amazing people who contribute to NeuralCut, the free and open-source video editor.",
|
||||
openGraph: {
|
||||
title: "Contributors - OpenCut",
|
||||
title: "Contributors - NeuralCut",
|
||||
description:
|
||||
"Meet the amazing people who contribute to OpenCut, the free and open-source video editor.",
|
||||
"Meet the amazing people who contribute to NeuralCut, the free and open-source video editor.",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
|
@ -70,7 +70,7 @@ export default async function ContributorsPage() {
|
|||
return (
|
||||
<BasePage
|
||||
title="Contributors"
|
||||
description="Meet the amazing people who contribute to OpenCut, the free and open-source video editor."
|
||||
description="Meet the amazing people who contribute to NeuralCut, the free and open-source video editor."
|
||||
>
|
||||
<div className="-mt-4 flex items-center justify-center gap-8 text-sm">
|
||||
<StatItem value={contributors.length} label="contributors" />
|
||||
|
|
@ -87,7 +87,7 @@ export default async function ContributorsPage() {
|
|||
<ExternalToolsSection />
|
||||
<GitHubContributeSection
|
||||
title="Join the community"
|
||||
description="OpenCut is built by developers like you. Every contribution, no matter how small, helps make video editing more accessible for everyone."
|
||||
description="NeuralCut is built by developers like you. Every contribution, no matter how small, helps make video editing more accessible for everyone."
|
||||
/>
|
||||
</div>
|
||||
</BasePage>
|
||||
|
|
@ -169,7 +169,7 @@ function AllContributorsSection({
|
|||
<div className="flex flex-col gap-2 text-center">
|
||||
<h2 className="text-2xl font-semibold">All contributors</h2>
|
||||
<p className="text-muted-foreground">
|
||||
Everyone who makes OpenCut better
|
||||
Everyone who makes NeuralCut better
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -211,7 +211,7 @@ function ExternalToolsSection() {
|
|||
<div className="flex flex-col gap-10">
|
||||
<div className="flex flex-col gap-2 text-center">
|
||||
<h2 className="text-2xl font-semibold">External tools</h2>
|
||||
<p className="text-muted-foreground">Tools we use to build OpenCut</p>
|
||||
<p className="text-muted-foreground">Tools we use to build NeuralCut</p>
|
||||
</div>
|
||||
|
||||
<div className="mx-auto grid max-w-4xl grid-cols-1 gap-6 sm:grid-cols-2">
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ function DegradedRendererBanner() {
|
|||
|
||||
return (
|
||||
<div className="bg-accent border-b h-9 flex items-center justify-center gap-2 text-xs text-muted-foreground">
|
||||
<span>For the best experience, open OpenCut in Chrome.</span>
|
||||
<span>For the best experience, open NeuralCut in Chrome.</span>
|
||||
<Button
|
||||
variant="text"
|
||||
size="icon"
|
||||
|
|
|
|||
|
|
@ -47,6 +47,54 @@
|
|||
--sidebar-border: hsl(0 0% 85.1%);
|
||||
--sidebar-ring: hsl(0 0% 16.9%);
|
||||
--sidebar: hsl(0 0% 98%);
|
||||
--export-ring: hsl(199, 89%, 60%);
|
||||
--export-gradient-from: hsl(215, 85%, 54%);
|
||||
--export-gradient-to: hsl(199, 91%, 59%);
|
||||
}
|
||||
|
||||
[data-palette="neuralcut"] {
|
||||
--background: hsl(220, 20%, 97%);
|
||||
--foreground: hsl(217, 23%, 14%);
|
||||
--card: hsl(220, 18%, 99%);
|
||||
--card-foreground: hsl(217, 23%, 14%);
|
||||
--popover: hsl(220, 18%, 99%);
|
||||
--popover-hover: hsl(220, 15%, 94%);
|
||||
--popover-foreground: hsl(217, 23%, 14%);
|
||||
--primary: hsl(342, 89%, 64%);
|
||||
--primary-foreground: hsl(0, 0%, 100%);
|
||||
--secondary: hsl(342, 40%, 95%);
|
||||
--secondary-border: hsl(342, 40%, 90%);
|
||||
--secondary-foreground: hsl(342, 80%, 45%);
|
||||
--muted: hsl(220, 10%, 85%);
|
||||
--muted-foreground: hsl(220, 10%, 48%);
|
||||
--accent: hsl(220, 15%, 94%);
|
||||
--accent-foreground: hsl(217, 23%, 14%);
|
||||
--destructive: hsl(0, 83%, 50%);
|
||||
--destructive-foreground: hsl(0, 0%, 100%);
|
||||
--constructive: hsl(141, 71%, 48%);
|
||||
--constructive-foreground: hsl(0, 0%, 100%);
|
||||
--caution: hsl(38, 92%, 50%);
|
||||
--caution-foreground: hsl(0, 0%, 10%);
|
||||
--border: hsl(220, 12%, 90%);
|
||||
--input: hsl(0, 0%, 100%);
|
||||
--ring: hsl(342, 89%, 64%);
|
||||
--chart-1: hsl(342 80% 55%);
|
||||
--chart-2: hsl(217 40% 45%);
|
||||
--chart-3: hsl(30 80% 55%);
|
||||
--chart-4: hsl(308 31% 45%);
|
||||
--chart-5: hsl(38 92% 55%);
|
||||
--sidebar-background: hsl(220, 18%, 96%);
|
||||
--sidebar-foreground: hsl(217, 23%, 14%);
|
||||
--sidebar-primary: hsl(217, 23%, 14%);
|
||||
--sidebar-primary-foreground: hsl(220, 12%, 90%);
|
||||
--sidebar-accent: hsl(220, 10%, 90%);
|
||||
--sidebar-accent-foreground: hsl(217, 23%, 14%);
|
||||
--sidebar-border: hsl(220, 10%, 90%);
|
||||
--sidebar-ring: hsl(217, 23%, 30%);
|
||||
--sidebar: hsl(220, 20%, 98%);
|
||||
--export-ring: hsl(342, 70%, 75%);
|
||||
--export-gradient-from: hsl(342, 89%, 50%);
|
||||
--export-gradient-to: hsl(342, 80%, 68%);
|
||||
}
|
||||
|
||||
.panel {
|
||||
|
|
@ -97,6 +145,43 @@
|
|||
--sidebar-border: hsl(0 0% 20%);
|
||||
--sidebar-ring: hsl(0 0% 83.1%);
|
||||
--sidebar: hsl(0 0% 6%);
|
||||
--export-ring: hsl(199, 89%, 60%);
|
||||
--export-gradient-from: hsl(215, 85%, 54%);
|
||||
--export-gradient-to: hsl(199, 91%, 59%);
|
||||
}
|
||||
|
||||
.dark[data-palette="neuralcut"] {
|
||||
--background: hsl(217, 23%, 14%);
|
||||
--foreground: hsl(220, 20%, 93%);
|
||||
--card: hsl(217, 20%, 17%);
|
||||
--card-foreground: hsl(220, 20%, 93%);
|
||||
--popover: hsl(217, 20%, 15%);
|
||||
--popover-hover: hsl(217, 18%, 22%);
|
||||
--popover-foreground: hsl(220, 20%, 95%);
|
||||
--secondary: hsl(342, 25%, 18%);
|
||||
--secondary-border: hsl(342, 25%, 23%);
|
||||
--secondary-foreground: hsl(342, 80%, 72%);
|
||||
--muted: hsl(217, 15%, 25%);
|
||||
--muted-foreground: hsl(220, 10%, 55%);
|
||||
--accent: hsl(217, 18%, 20%);
|
||||
--accent-foreground: hsl(220, 20%, 93%);
|
||||
--border: hsl(217, 18%, 22%);
|
||||
--input: hsl(217, 20%, 16%);
|
||||
--ring: hsl(342, 89%, 64%);
|
||||
--caution: hsl(38, 92%, 60%);
|
||||
--caution-foreground: hsl(0, 0%, 10%);
|
||||
--sidebar-background: hsl(217, 22%, 11%);
|
||||
--sidebar-foreground: hsl(220, 20%, 93%);
|
||||
--sidebar-primary: hsl(342, 89%, 64%);
|
||||
--sidebar-primary-foreground: hsl(0, 0%, 100%);
|
||||
--sidebar-accent: hsl(217, 15%, 20%);
|
||||
--sidebar-accent-foreground: hsl(220, 20%, 93%);
|
||||
--sidebar-border: hsl(217, 15%, 20%);
|
||||
--sidebar-ring: hsl(342, 89%, 64%);
|
||||
--sidebar: hsl(217, 22%, 12%);
|
||||
--export-ring: hsl(342, 70%, 75%);
|
||||
--export-gradient-from: hsl(342, 89%, 50%);
|
||||
--export-gradient-to: hsl(342, 80%, 68%);
|
||||
}
|
||||
|
||||
.dark .panel {
|
||||
|
|
@ -115,6 +200,42 @@
|
|||
--ring: hsl(0, 0%, 52%);
|
||||
}
|
||||
|
||||
[data-palette="neuralcut"] .panel {
|
||||
--background: hsl(220, 18%, 95%);
|
||||
--foreground: hsl(217, 23%, 14%);
|
||||
--card: hsl(220, 16%, 96%);
|
||||
--card-foreground: hsl(217, 23%, 14%);
|
||||
--primary-foreground: hsl(0, 0%, 100%);
|
||||
--secondary: hsl(342, 35%, 93%);
|
||||
--secondary-border: hsl(342, 35%, 88%);
|
||||
--secondary-foreground: hsl(342, 80%, 42%);
|
||||
--muted: hsl(220, 10%, 83%);
|
||||
--muted-foreground: hsl(220, 10%, 45%);
|
||||
--accent: hsl(220, 12%, 92%);
|
||||
--accent-foreground: hsl(217, 23%, 14%);
|
||||
--destructive-foreground: hsl(0, 0%, 100%);
|
||||
--constructive-foreground: hsl(0, 0%, 100%);
|
||||
--border: hsl(220, 10%, 88%);
|
||||
--input: hsl(220, 12%, 92%);
|
||||
--ring: hsl(342, 89%, 64%);
|
||||
}
|
||||
|
||||
.dark[data-palette="neuralcut"] .panel {
|
||||
--background: hsl(217, 20%, 18%);
|
||||
--foreground: hsl(220, 18%, 90%);
|
||||
--card: hsl(217, 18%, 19%);
|
||||
--card-foreground: hsl(220, 18%, 90%);
|
||||
--secondary: hsl(342, 30%, 15%);
|
||||
--secondary-border: hsl(342, 30%, 20%);
|
||||
--secondary-foreground: hsl(342, 80%, 68%);
|
||||
--muted: hsl(217, 12%, 28%);
|
||||
--accent: hsl(217, 15%, 22%);
|
||||
--accent-foreground: hsl(220, 18%, 90%);
|
||||
--border: hsl(217, 15%, 24%);
|
||||
--input: hsl(217, 15%, 24%);
|
||||
--ring: hsl(342, 89%, 64%);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
/*
|
||||
The default border color has changed to `currentcolor` in Tailwind CSS v4,
|
||||
|
|
@ -217,6 +338,10 @@
|
|||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
|
||||
--color-export-ring: var(--export-ring);
|
||||
--color-export-gradient-from: var(--export-gradient-from);
|
||||
--color-export-gradient-to: var(--export-gradient-to);
|
||||
|
||||
/* Animations */
|
||||
--animate-accordion-down: accordion-down 0.2s ease-out;
|
||||
--animate-accordion-up: accordion-up 0.2s ease-out;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { ThemeProvider } from "next-themes";
|
||||
import Script from "next/script";
|
||||
import "./globals.css";
|
||||
import { Toaster } from "../components/ui/sonner";
|
||||
|
|
@ -8,6 +7,7 @@ import { baseMetaData } from "./metadata";
|
|||
import { BotIdClient } from "botid/client";
|
||||
import { webEnv } from "@/lib/env/web";
|
||||
import { Inter } from "next/font/google";
|
||||
import { NeuralCutThemeProvider } from "@/lib/themes/theme-provider";
|
||||
|
||||
const siteFont = Inter({ subsets: ["latin"] });
|
||||
|
||||
|
|
@ -40,11 +40,7 @@ export default function RootLayout({
|
|||
)}
|
||||
</head>
|
||||
<body className={`${siteFont.className} font-sans antialiased`}>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
disableTransitionOnChange={true}
|
||||
>
|
||||
<NeuralCutThemeProvider>
|
||||
<TooltipProvider>
|
||||
<Toaster />
|
||||
<Script
|
||||
|
|
@ -61,7 +57,7 @@ export default function RootLayout({
|
|||
/>
|
||||
{children}
|
||||
</TooltipProvider>
|
||||
</ThemeProvider>
|
||||
</NeuralCutThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export const baseMetaData: Metadata = {
|
|||
url: SITE_INFO.openGraphImage,
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: "OpenCut Wordmark",
|
||||
alt: "NeuralCut Wordmark",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
@ -25,7 +25,7 @@ export const baseMetaData: Metadata = {
|
|||
card: "summary_large_image",
|
||||
title: SITE_INFO.title,
|
||||
description: SITE_INFO.description,
|
||||
creator: "@opencutapp",
|
||||
creator: "@neuralcut",
|
||||
images: [SITE_INFO.twitterImage],
|
||||
},
|
||||
pinterest: {
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ import { Separator } from "@/components/ui/separator";
|
|||
import { SOCIAL_LINKS } from "@/lib/site/social";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Privacy Policy - OpenCut",
|
||||
title: "Privacy Policy - NeuralCut",
|
||||
description:
|
||||
"Learn how OpenCut handles your data and privacy. Our commitment to protecting your information while you edit videos.",
|
||||
"Learn how NeuralCut handles your data and privacy. Our commitment to protecting your information while you edit videos.",
|
||||
openGraph: {
|
||||
title: "Privacy Policy - OpenCut",
|
||||
title: "Privacy Policy - NeuralCut",
|
||||
description:
|
||||
"Learn how OpenCut handles your data and privacy. Our commitment to protecting your information while you edit videos.",
|
||||
"Learn how NeuralCut handles your data and privacy. Our commitment to protecting your information while you edit videos.",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
|
@ -49,7 +49,7 @@ export default function PrivacyPage() {
|
|||
too - nothing is uploaded
|
||||
</li>
|
||||
<li>
|
||||
OpenCut does not currently require an account or login
|
||||
NeuralCut does not currently require an account or login
|
||||
</li>
|
||||
<li>Project data stays on your device, not our servers</li>
|
||||
<li>
|
||||
|
|
@ -88,7 +88,7 @@ export default function PrivacyPage() {
|
|||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-2xl font-semibold">Accounts & Authentication</h2>
|
||||
<p>
|
||||
OpenCut does not currently offer user accounts, login, or Google
|
||||
NeuralCut does not currently offer user accounts, login, or Google
|
||||
sign-in.
|
||||
</p>
|
||||
<p>
|
||||
|
|
@ -139,7 +139,7 @@ export default function PrivacyPage() {
|
|||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-2xl font-semibold">Third-Party Services</h2>
|
||||
<p>OpenCut integrates with these services:</p>
|
||||
<p>NeuralCut integrates with these services:</p>
|
||||
<ul className="list-disc space-y-2 pl-6">
|
||||
<li>
|
||||
<strong>Vercel:</strong> For hosting and content delivery
|
||||
|
|
@ -154,7 +154,7 @@ export default function PrivacyPage() {
|
|||
<h2 className="text-2xl font-semibold">Your Rights</h2>
|
||||
<p>You have complete control over your data:</p>
|
||||
<ul className="list-disc space-y-2 pl-6">
|
||||
<li>No account is required to use OpenCut today</li>
|
||||
<li>No account is required to use NeuralCut today</li>
|
||||
<li>Clear local storage to remove all saved projects</li>
|
||||
<li>Contact us with any privacy concerns</li>
|
||||
</ul>
|
||||
|
|
@ -163,7 +163,7 @@ export default function PrivacyPage() {
|
|||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-2xl font-semibold">Open Source Transparency</h2>
|
||||
<p>
|
||||
OpenCut is completely open source. You can review our code, see
|
||||
NeuralCut is completely open source. You can review our code, see
|
||||
exactly how we handle data, and even self-host the application if you
|
||||
prefer.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ const roadmapItems: RoadmapItem[] = [
|
|||
{
|
||||
title: "Native app (mobile/desktop)",
|
||||
description:
|
||||
"Native OpenCut apps for Mac, Windows, Linux, and iOS/Android.",
|
||||
"Native NeuralCut apps for Mac, Windows, Linux, and iOS/Android.",
|
||||
status: {
|
||||
text: "Not started",
|
||||
type: "default",
|
||||
|
|
@ -60,28 +60,28 @@ const roadmapItems: RoadmapItem[] = [
|
|||
];
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Roadmap - OpenCut",
|
||||
title: "Roadmap - NeuralCut",
|
||||
description:
|
||||
"See what's coming next for OpenCut - the free, open-source video editor that respects your privacy.",
|
||||
"See what's coming next for NeuralCut - the free, open-source video editor that respects your privacy.",
|
||||
openGraph: {
|
||||
title: "OpenCut Roadmap - What's Coming Next",
|
||||
title: "NeuralCut Roadmap - What's Coming Next",
|
||||
description:
|
||||
"See what's coming next for OpenCut - the free, open-source video editor that respects your privacy.",
|
||||
"See what's coming next for NeuralCut - the free, open-source video editor that respects your privacy.",
|
||||
type: "website",
|
||||
images: [
|
||||
{
|
||||
url: "/open-graph/roadmap.jpg",
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: "OpenCut Roadmap",
|
||||
alt: "NeuralCut Roadmap",
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: "OpenCut Roadmap - What's Coming Next",
|
||||
title: "NeuralCut Roadmap - What's Coming Next",
|
||||
description:
|
||||
"See what's coming next for OpenCut - the free, open-source video editor that respects your privacy.",
|
||||
"See what's coming next for NeuralCut - the free, open-source video editor that respects your privacy.",
|
||||
images: ["/open-graph/roadmap.jpg"],
|
||||
},
|
||||
};
|
||||
|
|
@ -90,7 +90,7 @@ export default function RoadmapPage() {
|
|||
return (
|
||||
<BasePage
|
||||
title="Roadmap"
|
||||
description={`What's coming next for OpenCut (last updated: ${LAST_UPDATED})`}
|
||||
description={`What's coming next for NeuralCut (last updated: ${LAST_UPDATED})`}
|
||||
>
|
||||
<div className="mx-auto flex max-w-4xl flex-col gap-16">
|
||||
<div className="flex flex-col gap-6">
|
||||
|
|
@ -100,7 +100,7 @@ export default function RoadmapPage() {
|
|||
</div>
|
||||
<GitHubContributeSection
|
||||
title="Want to help?"
|
||||
description="OpenCut is open source and built by the community. Every contribution,
|
||||
description="NeuralCut is open source and built by the community. Every contribution,
|
||||
no matter how small, helps us build the best free video editor
|
||||
possible."
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ import { LinkSquare02Icon } from "@hugeicons/core-free-icons";
|
|||
import { cn } from "@/utils/ui";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Sponsors - OpenCut",
|
||||
title: "Sponsors - NeuralCut",
|
||||
description:
|
||||
"Support OpenCut and help us build the future of free and open-source video editing.",
|
||||
"Support NeuralCut and help us build the future of free and open-source video editing.",
|
||||
openGraph: {
|
||||
title: "Sponsors - OpenCut",
|
||||
title: "Sponsors - NeuralCut",
|
||||
description:
|
||||
"Support OpenCut and help us build the future of free and open-source video editing.",
|
||||
"Support NeuralCut and help us build the future of free and open-source video editing.",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
|
@ -28,7 +28,7 @@ export default function SponsorsPage() {
|
|||
Sponsors
|
||||
</h1>
|
||||
<p className="text-muted-foreground mx-auto max-w-2xl text-xl leading-relaxed text-pretty">
|
||||
Support OpenCut and help us build the future of privacy-first video
|
||||
Support NeuralCut and help us build the future of privacy-first video
|
||||
editing.
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ import { Separator } from "@/components/ui/separator";
|
|||
import { SOCIAL_LINKS } from "@/lib/site/social";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Terms of Service - OpenCut",
|
||||
title: "Terms of Service - NeuralCut",
|
||||
description:
|
||||
"OpenCut's Terms of Service. Fair, transparent terms for our free and open-source video editor.",
|
||||
"NeuralCut's Terms of Service. Fair, transparent terms for our free and open-source video editor.",
|
||||
openGraph: {
|
||||
title: "Terms of Service - OpenCut",
|
||||
title: "Terms of Service - NeuralCut",
|
||||
description:
|
||||
"OpenCut's Terms of Service. Fair, transparent terms for our free and open-source video editor.",
|
||||
"NeuralCut's Terms of Service. Fair, transparent terms for our free and open-source video editor.",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
|
@ -83,7 +83,7 @@ export default function TermsPage() {
|
|||
processing happens locally on your device. We never see, store, or
|
||||
have access to your files. We make no claims to ownership, licensing,
|
||||
or rights over your videos, projects, or any content you create using
|
||||
OpenCut.
|
||||
NeuralCut.
|
||||
</p>
|
||||
<ul className="list-disc space-y-2 pl-6">
|
||||
<li>
|
||||
|
|
@ -91,25 +91,25 @@ export default function TermsPage() {
|
|||
</li>
|
||||
<li>You retain all intellectual property rights to your content</li>
|
||||
<li>You can export and use your content however you choose</li>
|
||||
<li>No watermarks, no licensing restrictions from OpenCut</li>
|
||||
<li>No watermarks, no licensing restrictions from NeuralCut</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-2xl font-semibold">How You Can Use OpenCut</h2>
|
||||
<p>OpenCut is free for personal and commercial use. You can:</p>
|
||||
<h2 className="text-2xl font-semibold">How You Can Use NeuralCut</h2>
|
||||
<p>NeuralCut is free for personal and commercial use. You can:</p>
|
||||
<ul className="list-disc space-y-2 pl-6">
|
||||
<li>
|
||||
Create videos for personal, educational, or commercial purposes
|
||||
</li>
|
||||
<li>Use OpenCut for client work and paid projects</li>
|
||||
<li>Share and distribute videos created with OpenCut</li>
|
||||
<li>Use NeuralCut for client work and paid projects</li>
|
||||
<li>Share and distribute videos created with NeuralCut</li>
|
||||
<li>
|
||||
Modify and distribute the OpenCut software (under MIT license)
|
||||
Modify and distribute the NeuralCut software (under MIT license)
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
You're responsible for how you use OpenCut and the content you create.
|
||||
You're responsible for how you use NeuralCut and the content you create.
|
||||
Don't use it for anything illegal in your jurisdiction.
|
||||
</p>
|
||||
</section>
|
||||
|
|
@ -119,14 +119,14 @@ export default function TermsPage() {
|
|||
<p>
|
||||
AI features like auto captions run entirely in your browser using
|
||||
on-device models. No content is uploaded to any server. These features
|
||||
are optional - you can use OpenCut without them.
|
||||
are optional - you can use NeuralCut without them.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-2xl font-semibold">Service</h2>
|
||||
<p>
|
||||
OpenCut does not currently require an account. The service is provided
|
||||
NeuralCut does not currently require an account. The service is provided
|
||||
"as is" without warranties. While we strive for reliability, we can't
|
||||
guarantee uninterrupted service.
|
||||
</p>
|
||||
|
|
@ -134,10 +134,10 @@ export default function TermsPage() {
|
|||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-2xl font-semibold">Open Source Benefits</h2>
|
||||
<p>Because OpenCut is open source, you have additional rights:</p>
|
||||
<p>Because NeuralCut is open source, you have additional rights:</p>
|
||||
<ul className="list-disc space-y-2 pl-6">
|
||||
<li>Review our code to see exactly how we handle your data</li>
|
||||
<li>Self-host OpenCut on your own servers</li>
|
||||
<li>Self-host NeuralCut on your own servers</li>
|
||||
<li>Modify the software to suit your needs</li>
|
||||
<li>Contribute improvements back to the community</li>
|
||||
</ul>
|
||||
|
|
@ -158,7 +158,7 @@ export default function TermsPage() {
|
|||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-2xl font-semibold">Limitations and Liability</h2>
|
||||
<p>
|
||||
OpenCut is provided free of charge. To the extent permitted by law:
|
||||
NeuralCut is provided free of charge. To the extent permitted by law:
|
||||
</p>
|
||||
<ul className="list-disc space-y-2 pl-6">
|
||||
<li>We're not liable for any loss of data or content</li>
|
||||
|
|
@ -178,7 +178,7 @@ export default function TermsPage() {
|
|||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-2xl font-semibold">Service Changes</h2>
|
||||
<p>We may update OpenCut and these terms:</p>
|
||||
<p>We may update NeuralCut and these terms:</p>
|
||||
<ul className="list-disc space-y-2 pl-6">
|
||||
<li>We'll notify you of significant changes to these terms</li>
|
||||
<li>Continued use means you accept any updates</li>
|
||||
|
|
@ -189,7 +189,7 @@ export default function TermsPage() {
|
|||
|
||||
<section className="flex flex-col gap-3">
|
||||
<h2 className="text-2xl font-semibold">Stopping Use</h2>
|
||||
<p>You can stop using OpenCut at any time:</p>
|
||||
<p>You can stop using NeuralCut at any time:</p>
|
||||
<ul className="list-disc space-y-2 pl-6">
|
||||
<li>Clear your browser data to remove local projects</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export function StoragePersistenceDialog() {
|
|||
runs low.
|
||||
</p>
|
||||
<p className="text-base text-muted-foreground">
|
||||
Allow OpenCut to protect them?
|
||||
Allow NeuralCut to protect them?
|
||||
</p>
|
||||
</DialogBody>
|
||||
<DialogFooter>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { useRouter } from "next/navigation";
|
|||
import { FaDiscord } from "react-icons/fa6";
|
||||
import { ExportButton } from "./export-button";
|
||||
import { FeedbackPopover } from "@/lib/feedback/components/feedback-popover";
|
||||
import { ThemeToggle } from "../theme-toggle";
|
||||
import { PaletteSelector } from "../palette-selector";
|
||||
import { DEFAULT_LOGO_URL } from "@/lib/site/brand";
|
||||
import { SOCIAL_LINKS } from "@/lib/site/social";
|
||||
import { toast } from "sonner";
|
||||
|
|
@ -37,7 +37,7 @@ export function EditorHeader() {
|
|||
<nav className="flex items-center gap-2">
|
||||
<FeedbackPopover />
|
||||
<ExportButton />
|
||||
<ThemeToggle />
|
||||
<PaletteSelector />
|
||||
</nav>
|
||||
</header>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export function ExportButton() {
|
|||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
"flex items-center gap-1.5 rounded-md bg-[#38BDF8] px-[0.12rem] py-[0.12rem] text-white",
|
||||
"flex items-center gap-1.5 rounded-md bg-export-ring px-[0.12rem] py-[0.12rem] text-white",
|
||||
hasProject ? "cursor-pointer" : "cursor-not-allowed opacity-50",
|
||||
)}
|
||||
onClick={hasProject ? () => setIsExportPopoverOpen(true) : undefined}
|
||||
|
|
@ -78,11 +78,11 @@ export function ExportButton() {
|
|||
}
|
||||
}}
|
||||
>
|
||||
<div className="relative flex items-center gap-1.5 rounded-[0.6rem] bg-linear-270 from-[#2567EC] to-[#37B6F7] px-4 py-1 shadow-[0_1px_3px_0px_rgba(0,0,0,0.65)]">
|
||||
<div className="relative flex items-center gap-1.5 rounded-[0.6rem] bg-linear-270 from-export-gradient-from to-export-gradient-to px-4 py-1 shadow-[0_1px_3px_0px_rgba(0,0,0,0.65)]">
|
||||
<HugeiconsIcon icon={TransitionTopIcon} className="z-50 size-3.5" />
|
||||
<span className="z-50 text-[0.875rem]">Export</span>
|
||||
<div className="absolute top-0 left-0 z-10 flex size-full items-center justify-center rounded-[0.6rem] bg-linear-to-t from-white/0 to-white/50">
|
||||
<div className="absolute top-[0.08rem] z-50 h-[calc(100%-2px)] w-[calc(100%-2px)] rounded-[0.6rem] bg-linear-270 from-[#2567EC] to-[#37B6F7]"></div>
|
||||
<div className="absolute top-[0.08rem] z-50 h-[calc(100%-2px)] w-[calc(100%-2px)] rounded-[0.6rem] bg-linear-270 from-export-gradient-from to-export-gradient-to"></div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export function MobileGate({ children }: MobileGateProps) {
|
|||
Desktop only (for now)
|
||||
</h1>
|
||||
<p className="text-muted-foreground text-sm leading-relaxed">
|
||||
OpenCut isn't optimized for mobile or iPad yet. Things will break
|
||||
NeuralCut isn't optimized for mobile or iPad yet. Things will break
|
||||
and the layout will be a mess. Come back on a desktop for the real
|
||||
experience.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -28,13 +28,13 @@ export function Onboarding() {
|
|||
const getStepTitle = () => {
|
||||
switch (step) {
|
||||
case 0:
|
||||
return "Welcome to OpenCut Beta! 🎉";
|
||||
return "Welcome to NeuralCut Beta! 🎉";
|
||||
case 1:
|
||||
return "⚠️ This is a super early beta!";
|
||||
case 2:
|
||||
return "🦋 Have fun testing!";
|
||||
default:
|
||||
return "OpenCut Onboarding";
|
||||
return "NeuralCut Onboarding";
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -44,8 +44,8 @@ export function Onboarding() {
|
|||
return (
|
||||
<div className="space-y-5">
|
||||
<div className="space-y-3">
|
||||
<Title title="Welcome to OpenCut Beta! 🎉" />
|
||||
<Description description="You're among the first to try OpenCut - the fully open source CapCut alternative." />
|
||||
<Title title="Welcome to NeuralCut Beta! 🎉" />
|
||||
<Description description="You're among the first to try NeuralCut - the fully open source CapCut alternative." />
|
||||
</div>
|
||||
<NextButton onClick={handleNext}>Next</NextButton>
|
||||
</div>
|
||||
|
|
@ -57,7 +57,7 @@ export function Onboarding() {
|
|||
<Title title={getStepTitle()} />
|
||||
<Description description="There's still a ton of things to do to make this editor amazing." />
|
||||
<Description description="A lot of features are still missing. We're working hard to build them out!" />
|
||||
<Description description="If you're curious, check out our roadmap [here](https://opencut.app/roadmap)" />
|
||||
<Description description="If you're curious, check out our roadmap [here](https://neuralcut.app/roadmap)" />
|
||||
</div>
|
||||
<NextButton onClick={handleNext}>Next</NextButton>
|
||||
</div>
|
||||
|
|
@ -68,7 +68,7 @@ export function Onboarding() {
|
|||
<div className="space-y-3">
|
||||
<Title title={getStepTitle()} />
|
||||
<Description
|
||||
description={`Join our [Discord](${SOCIAL_LINKS.discord}), chat with cool people and share feedback to help make OpenCut the best editor ever.`}
|
||||
description={`Join our [Discord](${SOCIAL_LINKS.discord}), chat with cool people and share feedback to help make NeuralCut the best editor ever.`}
|
||||
/>
|
||||
</div>
|
||||
<NextButton onClick={handleClose}>Finish</NextButton>
|
||||
|
|
|
|||
|
|
@ -41,12 +41,12 @@ export function Footer() {
|
|||
<div className="mb-4 flex items-center justify-start gap-2">
|
||||
<Image
|
||||
src={DEFAULT_LOGO_URL}
|
||||
alt="OpenCut"
|
||||
width={24}
|
||||
height={24}
|
||||
className="invert dark:invert-0"
|
||||
/>
|
||||
<span className="text-lg font-bold">OpenCut</span>
|
||||
alt="NeuralCut"
|
||||
width={24}
|
||||
height={24}
|
||||
className="invert dark:invert-0"
|
||||
/>
|
||||
<span className="text-lg font-bold">NeuralCut</span>
|
||||
</div>
|
||||
<p className="text-muted-foreground mb-5 text-sm md:text-left">
|
||||
The privacy-first video editor that feels simple to use.
|
||||
|
|
@ -114,7 +114,7 @@ export function Footer() {
|
|||
<div className="flex flex-col items-start justify-between gap-4 pt-2 md:flex-row">
|
||||
<div className="text-muted-foreground flex items-center gap-4 text-sm">
|
||||
<span>
|
||||
© {new Date().getFullYear()} OpenCut, All Rights Reserved
|
||||
© {new Date().getFullYear()} NeuralCut, All Rights Reserved
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { motion } from "motion/react";
|
|||
import { Button } from "./ui/button";
|
||||
import { ArrowRight } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { ThemeToggle } from "./theme-toggle";
|
||||
import { PaletteSelector } from "./palette-selector";
|
||||
import {
|
||||
Copy01Icon,
|
||||
Download01Icon,
|
||||
|
|
@ -57,7 +57,7 @@ export function Header() {
|
|||
<Link href="/" className="flex items-center gap-3">
|
||||
<Image
|
||||
src={DEFAULT_LOGO_URL}
|
||||
alt="OpenCut Logo"
|
||||
alt="NeuralCut Logo"
|
||||
className="invert dark:invert-0"
|
||||
width={32}
|
||||
height={32}
|
||||
|
|
@ -79,7 +79,7 @@ export function Header() {
|
|||
onClick={() => {
|
||||
const a = document.createElement("a");
|
||||
a.href = DEFAULT_LOGO_URL;
|
||||
a.download = "opencut-logo.svg";
|
||||
a.download = "neuralcut-logo.svg";
|
||||
a.click();
|
||||
}}
|
||||
>
|
||||
|
|
@ -130,7 +130,7 @@ export function Header() {
|
|||
<ArrowRight className="size-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
<ThemeToggle />
|
||||
<PaletteSelector />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
|
@ -182,13 +182,8 @@ export function Header() {
|
|||
</motion.div>
|
||||
))}
|
||||
</nav>
|
||||
<ThemeToggle
|
||||
className="absolute right-8 bottom-8 size-10"
|
||||
iconClassName="!size-[1.2rem]"
|
||||
onToggle={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
<PaletteSelector
|
||||
className="absolute right-8 bottom-8 [&>button]:size-10 [&_.hugeicons-icon]:!size-[1.2rem]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export function Hero() {
|
|||
src="/landing-page-dark.png"
|
||||
height={1903.5}
|
||||
width={1269}
|
||||
alt="OpenCut video editor landing page background"
|
||||
alt="NeuralCut video editor landing page background"
|
||||
/>
|
||||
<div className="mx-auto flex w-full max-w-3xl flex-1 flex-col justify-center">
|
||||
<div className="inline-block text-4xl font-bold tracking-tighter md:text-[4rem]">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
"use client";
|
||||
|
||||
import { useTheme } from "next-themes";
|
||||
import { useThemeStore, PALETTES } from "@/lib/themes";
|
||||
import { cn } from "@/utils/ui";
|
||||
import { CheckmarkCircle01Icon } from "@hugeicons/core-free-icons";
|
||||
import { HugeiconsIcon } from "@hugeicons/react";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Sun03Icon } from "@hugeicons/core-free-icons";
|
||||
|
||||
export function PaletteSelector({ className }: { className?: string }) {
|
||||
const { theme, setTheme } = useTheme();
|
||||
const { paletteId, setPalette } = useThemeStore();
|
||||
const activePalette = PALETTES.find((p) => p.id === paletteId);
|
||||
|
||||
return (
|
||||
<div className={cn("flex items-center gap-1", className)}>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
className="size-8"
|
||||
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
|
||||
>
|
||||
<HugeiconsIcon icon={Sun03Icon} className="!size-[1.1rem]" />
|
||||
</Button>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="ghost" size="icon" className="size-8 gap-0 p-1">
|
||||
<div className="flex gap-0.5">
|
||||
{activePalette?.preview && (
|
||||
<>
|
||||
<div
|
||||
className="size-3 rounded-full border border-border"
|
||||
style={{ backgroundColor: activePalette.preview.primary }}
|
||||
/>
|
||||
<div
|
||||
className="size-3 rounded-full border border-border"
|
||||
style={{ backgroundColor: activePalette.preview.accent }}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent align="end" className="w-48 p-2">
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-muted-foreground px-2 text-xs font-medium">
|
||||
Palette
|
||||
</p>
|
||||
{PALETTES.map((palette) => (
|
||||
<button
|
||||
key={palette.id}
|
||||
type="button"
|
||||
className={cn(
|
||||
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors hover:bg-accent",
|
||||
paletteId === palette.id && "bg-accent",
|
||||
)}
|
||||
onClick={() => setPalette(palette.id)}
|
||||
>
|
||||
<div className="flex gap-0.5">
|
||||
<div
|
||||
className="size-3.5 rounded-full border border-border"
|
||||
style={{ backgroundColor: palette.preview.primary }}
|
||||
/>
|
||||
<div
|
||||
className="size-3.5 rounded-full border border-border"
|
||||
style={{ backgroundColor: palette.preview.background }}
|
||||
/>
|
||||
<div
|
||||
className="size-3.5 rounded-full border border-border"
|
||||
style={{ backgroundColor: palette.preview.accent }}
|
||||
/>
|
||||
</div>
|
||||
<span className="flex-1 text-left">{palette.name}</span>
|
||||
{paletteId === palette.id && (
|
||||
<HugeiconsIcon
|
||||
icon={CheckmarkCircle01Icon}
|
||||
className="text-primary !size-4"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
const DISMISSED_KEY = "opencut-storage-persist-dismissed";
|
||||
const DISMISSED_KEY = "neuralcut-storage-persist-dismissed";
|
||||
|
||||
function isFirefox(): boolean {
|
||||
return navigator.userAgent.toLowerCase().includes("firefox");
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export const auth = betterAuth({
|
|||
},
|
||||
},
|
||||
baseURL: webEnv.NEXT_PUBLIC_SITE_URL,
|
||||
appName: "OpenCut",
|
||||
appName: "NeuralCut",
|
||||
trustedOrigins: [webEnv.NEXT_PUBLIC_SITE_URL],
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export const SITE_URL = "https://opencut.app";
|
||||
export const SITE_URL = "https://neuralcut.app";
|
||||
|
||||
export const SITE_INFO = {
|
||||
title: "OpenCut",
|
||||
title: "NeuralCut",
|
||||
description:
|
||||
"A simple but powerful video editor that gets the job done. In your browser.",
|
||||
url: SITE_URL,
|
||||
|
|
|
|||
|
|
@ -11,13 +11,13 @@ export const EXTERNAL_TOOLS: ExternalTool[] = [
|
|||
{
|
||||
name: "Marble",
|
||||
description:
|
||||
"Modern headless CMS for content management and the blog for OpenCut",
|
||||
"Modern headless CMS for content management and the blog for NeuralCut",
|
||||
url: "https://marblecms.com?utm_source=opencut",
|
||||
icon: OcMarbleIcon,
|
||||
},
|
||||
{
|
||||
name: "Databuddy",
|
||||
description: "GDPR compliant analytics and user insights for OpenCut",
|
||||
description: "GDPR compliant analytics and user insights for NeuralCut",
|
||||
url: "https://databuddy.cc?utm_source=opencut",
|
||||
icon: OcDataBuddyIcon,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export const SPONSORS: Sponsor[] = [
|
|||
name: "Vercel",
|
||||
url: "https://vercel.com?utm_source=opencut",
|
||||
logo: "/logos/others/vercel.svg",
|
||||
description: "Platform where we deploy and host OpenCut.",
|
||||
description: "Platform where we deploy and host NeuralCut.",
|
||||
invertOnDark: true,
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
export { useThemeStore } from "./theme-store";
|
||||
export { PALETTES, getPaletteById } from "./palettes";
|
||||
export type { PaletteMeta } from "./types";
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import type { PaletteMeta } from "../types";
|
||||
|
||||
export const CLASSIC_PALETTE: PaletteMeta = {
|
||||
id: "classic",
|
||||
name: "Classic",
|
||||
preview: {
|
||||
primary: "#15A0E6",
|
||||
background: "#0D0D0D",
|
||||
accent: "#333333",
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { NEURALCUT_PALETTE } from "./neuralcut";
|
||||
import { CLASSIC_PALETTE } from "./classic";
|
||||
import type { PaletteMeta } from "../types";
|
||||
|
||||
export const PALETTES: PaletteMeta[] = [NEURALCUT_PALETTE, CLASSIC_PALETTE];
|
||||
|
||||
export function getPaletteById(id: string): PaletteMeta | undefined {
|
||||
return PALETTES.find((p) => p.id === id);
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import type { PaletteMeta } from "../types";
|
||||
|
||||
export const NEURALCUT_PALETTE: PaletteMeta = {
|
||||
id: "neuralcut",
|
||||
name: "NeuralCut",
|
||||
preview: {
|
||||
primary: "#F55385",
|
||||
background: "#1B212B",
|
||||
accent: "#BC466D",
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { ThemeProvider } from "next-themes";
|
||||
import { useThemeStore } from "@/lib/themes";
|
||||
|
||||
const PALETTE_SCRIPT = `
|
||||
(function(){
|
||||
try {
|
||||
var s = localStorage.getItem('neuralcut-theme');
|
||||
if (s) {
|
||||
var d = JSON.parse(s);
|
||||
if (d && d.state && d.state.paletteId) {
|
||||
document.documentElement.setAttribute('data-palette', d.state.paletteId);
|
||||
}
|
||||
} else {
|
||||
document.documentElement.setAttribute('data-palette', 'neuralcut');
|
||||
}
|
||||
} catch(e) {
|
||||
document.documentElement.setAttribute('data-palette', 'neuralcut');
|
||||
}
|
||||
})();
|
||||
`;
|
||||
|
||||
export function NeuralCutThemeProvider({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const paletteId = useThemeStore((s) => s.paletteId);
|
||||
|
||||
useEffect(() => {
|
||||
document.documentElement.setAttribute("data-palette", paletteId);
|
||||
}, [paletteId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<script dangerouslySetInnerHTML={{ __html: PALETTE_SCRIPT }} />
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
disableTransitionOnChange
|
||||
>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
"use client";
|
||||
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
import { NEURALCUT_PALETTE } from "./palettes/neuralcut";
|
||||
|
||||
interface ThemeState {
|
||||
paletteId: string;
|
||||
setPalette: (id: string) => void;
|
||||
}
|
||||
|
||||
export const useThemeStore = create<ThemeState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
paletteId: NEURALCUT_PALETTE.id,
|
||||
setPalette: (id: string) => set({ paletteId: id }),
|
||||
}),
|
||||
{
|
||||
name: "neuralcut-theme",
|
||||
},
|
||||
),
|
||||
);
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
export interface PaletteMeta {
|
||||
id: string;
|
||||
name: string;
|
||||
preview: { primary: string; background: string; accent: string };
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@ export const useKeybindingsStore = create<KeybindingsState>()(
|
|||
},
|
||||
}),
|
||||
{
|
||||
name: "opencut-keybindings",
|
||||
name: "neuralcut-keybindings",
|
||||
version: CURRENT_VERSION,
|
||||
partialize: (state) => ({
|
||||
keybindings: state.keybindings,
|
||||
|
|
|
|||
16
package.json
16
package.json
|
|
@ -1,25 +1,25 @@
|
|||
{
|
||||
"name": "opencut",
|
||||
"name": "neuralcut",
|
||||
"packageManager": "bun@1.2.18",
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"packages/*"
|
||||
],
|
||||
"scripts": {
|
||||
"build:tools": "turbo run build --filter=@opencut/tools",
|
||||
"build:tools": "turbo run build --filter=@neuralcut/tools",
|
||||
"build:wasm": "wasm-pack build rust/wasm --target bundler --out-dir pkg",
|
||||
"build:web": "turbo run build --filter=@opencut/web",
|
||||
"deploy:web": "turbo run deploy --filter=@opencut/web",
|
||||
"dev:tools": "turbo run dev --filter=@opencut/tools",
|
||||
"build:web": "turbo run build --filter=@neuralcut/web",
|
||||
"deploy:web": "turbo run deploy --filter=@neuralcut/web",
|
||||
"dev:tools": "turbo run dev --filter=@neuralcut/tools",
|
||||
"dev:wasm": "cargo watch -w rust/crates -w rust/wasm/src -s 'wasm-pack build rust/wasm --target bundler --out-dir pkg'",
|
||||
"dev:web": "turbo run dev --filter=@opencut/web",
|
||||
"dev:web": "turbo run dev --filter=@neuralcut/web",
|
||||
"format:web": "biome format apps/web/src/services/renderer --write --max-diagnostics=1000",
|
||||
"generate:fonts": "npx tsx apps/web/scripts/generate-font-sprites.ts",
|
||||
"lint:web": "biome lint apps/web/src --max-diagnostics=1000",
|
||||
"lint:web:fix": "biome lint apps/web/src --write --unsafe --max-diagnostics=1000",
|
||||
"preview:web": "turbo run preview --filter=@opencut/web",
|
||||
"preview:web": "turbo run preview --filter=@neuralcut/web",
|
||||
"publish:wasm": "bun run build:wasm && npm publish rust/wasm/pkg --access public",
|
||||
"start:tools": "turbo run start --filter=@opencut/tools",
|
||||
"start:tools": "turbo run start --filter=@neuralcut/tools",
|
||||
"test": "bun test"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
|
|||
Loading…
Reference in New Issue