mirror of
https://github.com/jnsahaj/tweakcn.git
synced 2026-09-21 12:50:29 +08:00
fix: Computing unsaved changes. now based on matching current preset with styles
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Copy, Check, Heart } from "lucide-react";
|
||||
import { ThemeEditorState } from "@/types/editor";
|
||||
@@ -38,9 +38,7 @@ const CodePanel: React.FC<CodePanelProps> = ({ themeEditorState }) => {
|
||||
const setPackageManager = usePreferencesStore(
|
||||
(state) => state.setPackageManager
|
||||
);
|
||||
const hasUnsavedChanges = useEditorStore(
|
||||
(state) => state.hasThemeChangedFromCheckpoint
|
||||
);
|
||||
const hasUnsavedChanges = useEditorStore((state) => state.hasUnsavedChanges);
|
||||
|
||||
const isSavedPreset = useThemePresetStore(
|
||||
(state) => preset && state.getPreset(preset)?.source === "SAVED"
|
||||
@@ -101,27 +99,17 @@ const CodePanel: React.FC<CodePanelProps> = ({ themeEditorState }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const showRegistryCommand = useMemo(() => {
|
||||
return preset && preset !== "default" && !hasUnsavedChanges();
|
||||
}, [preset, hasUnsavedChanges]);
|
||||
|
||||
return (
|
||||
<div className="h-full flex flex-col">
|
||||
<div className="flex-none mb-4">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<h2 className="text-lg font-semibold">Theme Code</h2>
|
||||
</div>
|
||||
{preset && preset !== "default" && hasUnsavedChanges() && (
|
||||
<Alert className="mt-4">
|
||||
<AlertTitle>You have unsaved changes.</AlertTitle>
|
||||
<AlertDescription className="flex flex-col gap-2 mt-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="flex items-center gap-1 px-2 py-0.5 border rounded-md">
|
||||
<Heart className="size-3.5" />
|
||||
<span>Save</span>
|
||||
</div>
|
||||
your theme to get the registry command.
|
||||
</div>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
{preset && preset !== "default" && !hasUnsavedChanges() && (
|
||||
{showRegistryCommand ? (
|
||||
<div className="mt-4 rounded-md overflow-hidden border">
|
||||
<div className="flex border-b">
|
||||
{(["pnpm", "npm", "yarn", "bun"] as const).map((pm) => (
|
||||
@@ -158,13 +146,26 @@ const CodePanel: React.FC<CodePanelProps> = ({ themeEditorState }) => {
|
||||
<ScrollArea className="w-full">
|
||||
<div className="whitespace-nowrap overflow-y-hidden pb-2">
|
||||
<code className="text-sm font-mono">
|
||||
{getRegistryCommand(preset)}
|
||||
{getRegistryCommand(preset as string)}
|
||||
</code>
|
||||
</div>
|
||||
<ScrollBar orientation="horizontal" />
|
||||
</ScrollArea>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<Alert className="mt-4">
|
||||
<AlertTitle>You have unsaved changes.</AlertTitle>
|
||||
<AlertDescription className="flex flex-col gap-2 mt-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="flex items-center gap-1 px-2 py-0.5 border rounded-md">
|
||||
<Heart className="size-3.5" />
|
||||
<span>Save</span>
|
||||
</div>
|
||||
your theme to get the registry command.
|
||||
</div>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 mb-4 ">
|
||||
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
} from "../ui/tooltip";
|
||||
import { Input } from "../ui/input";
|
||||
import { Badge } from "../ui/badge";
|
||||
import { cn, isDeepEqual } from "@/lib/utils";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface ThemePresetSelectProps {
|
||||
presets: Record<string, ThemePreset>;
|
||||
@@ -168,7 +168,7 @@ const ThemePresetSelect: React.FC<ThemePresetSelectProps> = ({
|
||||
currentPreset,
|
||||
onPresetChange,
|
||||
}) => {
|
||||
const { themeState, hasThemeChangedFromCheckpoint } = useEditorStore();
|
||||
const { themeState, hasUnsavedChanges } = useEditorStore();
|
||||
const { theme, toggleTheme } = useTheme();
|
||||
const mode = themeState.currentMode;
|
||||
const [search, setSearch] = useState("");
|
||||
@@ -256,19 +256,6 @@ const ThemePresetSelect: React.FC<ThemePresetSelectProps> = ({
|
||||
);
|
||||
}, [filteredPresets, isSavedTheme]);
|
||||
|
||||
const hasUnsavedChanges = useMemo(() => {
|
||||
return (
|
||||
hasThemeChangedFromCheckpoint() ||
|
||||
(!currentPreset &&
|
||||
!isDeepEqual(themeState.styles, presets["default"]?.styles))
|
||||
);
|
||||
}, [
|
||||
hasThemeChangedFromCheckpoint,
|
||||
currentPreset,
|
||||
themeState.styles,
|
||||
presets,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<TooltipProvider>
|
||||
@@ -290,7 +277,7 @@ const ThemePresetSelect: React.FC<ThemePresetSelectProps> = ({
|
||||
{value !== "default" &&
|
||||
value &&
|
||||
isSavedTheme(value) &&
|
||||
!hasUnsavedChanges && (
|
||||
!hasUnsavedChanges() && (
|
||||
<div className="rounded-full bg-muted p-1">
|
||||
<Heart
|
||||
className="size-1"
|
||||
@@ -300,7 +287,7 @@ const ThemePresetSelect: React.FC<ThemePresetSelectProps> = ({
|
||||
</div>
|
||||
)}
|
||||
<span className="capitalize font-medium">
|
||||
{hasUnsavedChanges ? (
|
||||
{hasUnsavedChanges() ? (
|
||||
<>Custom (Unsaved)</>
|
||||
) : (
|
||||
presets[value || "default"]?.label || "default"
|
||||
|
||||
@@ -13,6 +13,7 @@ interface EditorStore {
|
||||
saveThemeCheckpoint: () => void;
|
||||
restoreThemeCheckpoint: () => void;
|
||||
hasThemeChangedFromCheckpoint: () => boolean;
|
||||
hasUnsavedChanges: () => boolean;
|
||||
}
|
||||
|
||||
export const useEditorStore = create<EditorStore>()(
|
||||
@@ -53,6 +54,13 @@ export const useEditorStore = create<EditorStore>()(
|
||||
const checkpoint = get().themeCheckpoint;
|
||||
return !isDeepEqual(get().themeState, checkpoint);
|
||||
},
|
||||
hasUnsavedChanges: () => {
|
||||
const themeState = get().themeState;
|
||||
const presetThemeStyles = getPresetThemeStyles(
|
||||
themeState.preset ?? "default"
|
||||
);
|
||||
return !isDeepEqual(themeState.styles, presetThemeStyles);
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: "editor-storage",
|
||||
|
||||
Reference in New Issue
Block a user