mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-08 18:05:10 +00:00
a25acbec7c
* feat(editor): add useComposeDiffPreviewEnabled hook * feat(editor): add ComposeDiffPreviewDialog component * fix(editor): replace HTML entity with Unicode arrow in ComposeDiffPreviewDialog * feat(editor): add diff preview toggle to Appearance settings Added a new 'Diff preview before save' toggle in the Display section of the Appearance settings panel. Users can now enable or disable the side-by-side diff view before compose and env file edits are saved to disk. * feat(editor): wire diff preview dialog into compose save flow * fix(editor): snapshot diff content at open time and fix event name - Fix useComposeDiffPreviewEnabled and useDeployFeedbackEnabled to use the canonical SENCHO_SETTINGS_CHANGED constant from @/lib/events instead of the hardcoded string literal (wrong value) - Snapshot language, original, modified, and fileName into diffPreview state at click time to prevent tab-switching from corrupting dialog content mid-review - Remove React.MouseEvent from diffPreview state; pass a no-op stub to deployStack in the confirm path (preventDefault/stopPropagation are no-ops on an already-settled event anyway) - Add diff-modal screenshot and document the feature in editor.mdx and settings.mdx * docs(editor): add settings-toggle screenshot for diff preview feature
47 lines
1.6 KiB
TypeScript
47 lines
1.6 KiB
TypeScript
import { useCallback, useEffect, useState } from 'react';
|
|
import { SENCHO_SETTINGS_CHANGED } from '@/lib/events';
|
|
|
|
export const DEPLOY_FEEDBACK_KEY = 'sencho.deploy-feedback.enabled';
|
|
|
|
function readStored(): boolean {
|
|
if (typeof window === 'undefined') return false;
|
|
try {
|
|
return window.localStorage.getItem(DEPLOY_FEEDBACK_KEY) === 'true';
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function useDeployFeedbackEnabled(): [boolean, (next: boolean) => void] {
|
|
const [enabled, setEnabledState] = useState<boolean>(readStored);
|
|
|
|
useEffect(() => {
|
|
function onSettingsChanged() {
|
|
setEnabledState(readStored());
|
|
}
|
|
window.addEventListener(SENCHO_SETTINGS_CHANGED, onSettingsChanged);
|
|
return () => window.removeEventListener(SENCHO_SETTINGS_CHANGED, onSettingsChanged);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
function onStorage(event: StorageEvent) {
|
|
if (event.key !== DEPLOY_FEEDBACK_KEY) return;
|
|
setEnabledState(event.newValue === 'true');
|
|
}
|
|
window.addEventListener('storage', onStorage);
|
|
return () => window.removeEventListener('storage', onStorage);
|
|
}, []);
|
|
|
|
const setEnabled = useCallback((next: boolean) => {
|
|
try {
|
|
window.localStorage.setItem(DEPLOY_FEEDBACK_KEY, next ? 'true' : 'false');
|
|
} catch {
|
|
// ignore; localStorage may be unavailable (private mode, quota)
|
|
}
|
|
setEnabledState(next);
|
|
window.dispatchEvent(new CustomEvent(SENCHO_SETTINGS_CHANGED));
|
|
}, []);
|
|
|
|
return [enabled, setEnabled];
|
|
}
|