From 696e72323bd4e16bf31267eab107e3f34065e2dc Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Fri, 24 May 2024 17:36:48 -0700 Subject: [PATCH] More theme stuff --- index.html | 2 +- src-tauri/capabilities/capabilities.json | 1 + src-tauri/gen/schemas/capabilities.json | 2 +- src-tauri/src/lib.rs | 10 +++ src-tauri/src/window_menu.rs | 18 ++--- .../components/Settings/SettingsDesign.tsx | 67 +++++++++++++++++++ .../components/Settings/SettingsDialog.tsx | 1 - src-web/components/core/Editor/Editor.css | 4 +- .../core/Editor/twig/placeholder.ts | 6 +- src-web/components/core/Tabs/Tabs.tsx | 14 +--- src-web/hooks/usePreferredAppearance.ts | 18 +++++ src-web/hooks/useResolvedAppearance.ts | 15 ++--- src-web/lib/theme/themes/catppuccin.ts | 10 +-- src-web/lib/theme/themes/github.ts | 14 ++-- src-web/lib/theme/themes/monokai-pro.ts | 2 +- src-web/lib/theme/themes/rose-pine.ts | 4 +- src-web/lib/theme/window.ts | 22 +++--- 17 files changed, 142 insertions(+), 68 deletions(-) create mode 100644 src-web/hooks/usePreferredAppearance.ts diff --git a/index.html b/index.html index ca2d48a1..f966d930 100644 --- a/index.html +++ b/index.html @@ -15,7 +15,7 @@ @media (prefers-color-scheme: dark) { html, body { - background-color: black; + background-color: #1b1a29; } } diff --git a/src-tauri/capabilities/capabilities.json b/src-tauri/capabilities/capabilities.json index 0e65fdf3..a22cca63 100644 --- a/src-tauri/capabilities/capabilities.json +++ b/src-tauri/capabilities/capabilities.json @@ -48,6 +48,7 @@ "window:allow-set-title", "window:allow-start-dragging", "window:allow-unmaximize", + "window:allow-theme", "clipboard-manager:allow-read-text", "clipboard-manager:allow-write-text" ] diff --git a/src-tauri/gen/schemas/capabilities.json b/src-tauri/gen/schemas/capabilities.json index b09e85af..b3253e66 100644 --- a/src-tauri/gen/schemas/capabilities.json +++ b/src-tauri/gen/schemas/capabilities.json @@ -1 +1 @@ -{"main":{"identifier":"main","description":"Main permissions","local":true,"windows":["*"],"permissions":["os:allow-os-type","event:allow-emit","clipboard-manager:allow-write-text","clipboard-manager:allow-read-text","dialog:allow-open","dialog:allow-save","event:allow-listen","event:allow-unlisten","fs:allow-read-file","fs:allow-read-text-file",{"identifier":"fs:scope","allow":[{"path":"$APPDATA"},{"path":"$APPDATA/**"}]},"shell:allow-open",{"identifier":"shell:allow-execute","allow":[{"args":true,"name":"protoc","sidecar":true}]},"window:allow-close","window:allow-is-fullscreen","window:allow-maximize","window:allow-minimize","window:allow-toggle-maximize","window:allow-set-decorations","window:allow-set-title","window:allow-start-dragging","window:allow-unmaximize","clipboard-manager:allow-read-text","clipboard-manager:allow-write-text"]}} \ No newline at end of file +{"main":{"identifier":"main","description":"Main permissions","local":true,"windows":["*"],"permissions":["os:allow-os-type","event:allow-emit","clipboard-manager:allow-write-text","clipboard-manager:allow-read-text","dialog:allow-open","dialog:allow-save","event:allow-listen","event:allow-unlisten","fs:allow-read-file","fs:allow-read-text-file",{"identifier":"fs:scope","allow":[{"path":"$APPDATA"},{"path":"$APPDATA/**"}]},"shell:allow-open",{"identifier":"shell:allow-execute","allow":[{"args":true,"name":"protoc","sidecar":true}]},"window:allow-close","window:allow-is-fullscreen","window:allow-maximize","window:allow-minimize","window:allow-toggle-maximize","window:allow-set-decorations","window:allow-set-title","window:allow-start-dragging","window:allow-unmaximize","window:allow-theme","clipboard-manager:allow-read-text","clipboard-manager:allow-write-text"]}} \ No newline at end of file diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index b7bb2a8d..6cffbea4 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1292,6 +1292,15 @@ async fn cmd_update_folder(folder: Folder, w: WebviewWindow) -> Result Result<(), String> { + if !is_dev() { + panic!("Cannot write arbitrary files when not in dev mode"); + } + + fs::write(pathname, contents).map_err(|e| e.to_string()) +} + #[tauri::command] async fn cmd_delete_folder(w: WebviewWindow, folder_id: &str) -> Result { delete_folder(&w, folder_id) @@ -1669,6 +1678,7 @@ pub fn run() { cmd_update_http_request, cmd_update_settings, cmd_update_workspace, + cmd_write_file_dev, ]) .build(tauri::generate_context!()) .expect("error while running tauri application") diff --git a/src-tauri/src/window_menu.rs b/src-tauri/src/window_menu.rs index 7b218400..4c74a764 100644 --- a/src-tauri/src/window_menu.rs +++ b/src-tauri/src/window_menu.rs @@ -107,15 +107,15 @@ pub fn app_menu(app_handle: &AppHandle) -> tauri::Result> { &PredefinedMenuItem::fullscreen(app_handle, None)?, #[cfg(target_os = "macos")] &PredefinedMenuItem::separator(app_handle)?, - // &MenuItemBuilder::with_id("zoom_reset".to_string(), "Zoom to Actual Size") - // .accelerator("CmdOrCtrl+0") - // .build(app_handle)?, - // &MenuItemBuilder::with_id("zoom_in".to_string(), "Zoom In") - // .accelerator("CmdOrCtrl+=") - // .build(app_handle)?, - // &MenuItemBuilder::with_id("zoom_out".to_string(), "Zoom Out") - // .accelerator("CmdOrCtrl+-") - // .build(app_handle)?, + &MenuItemBuilder::with_id("zoom_reset".to_string(), "Zoom to Actual Size") + .accelerator("CmdOrCtrl+0") + .build(app_handle)?, + &MenuItemBuilder::with_id("zoom_in".to_string(), "Zoom In") + .accelerator("CmdOrCtrl+=") + .build(app_handle)?, + &MenuItemBuilder::with_id("zoom_out".to_string(), "Zoom Out") + .accelerator("CmdOrCtrl+-") + .build(app_handle)?, ], )?, &window_menu, diff --git a/src-web/components/Settings/SettingsDesign.tsx b/src-web/components/Settings/SettingsDesign.tsx index 50f401f9..e0eb80d9 100644 --- a/src-web/components/Settings/SettingsDesign.tsx +++ b/src-web/components/Settings/SettingsDesign.tsx @@ -1,12 +1,25 @@ +import { invoke } from '@tauri-apps/api/core'; +import { open } from '@tauri-apps/plugin-dialog'; import React from 'react'; +import { useLocalStorage } from 'react-use'; +import { useThemes } from '../../hooks/useThemes'; import { capitalize } from '../../lib/capitalize'; +import { catppuccinMacchiato } from '../../lib/theme/themes/catppuccin'; +import { githubLight } from '../../lib/theme/themes/github'; +import { monokaiProDefault } from '../../lib/theme/themes/monokai-pro'; +import { rosePineDefault } from '../../lib/theme/themes/rose-pine'; +import { yaakDark } from '../../lib/theme/themes/yaak'; +import { getThemeCSS } from '../../lib/theme/window'; import { Banner } from '../core/Banner'; import { Button } from '../core/Button'; import { Editor } from '../core/Editor'; import type { IconProps } from '../core/Icon'; import { Icon } from '../core/Icon'; import { IconButton } from '../core/IconButton'; +import { InlineCode } from '../core/InlineCode'; import { Input } from '../core/Input'; +import { Separator } from '../core/Separator'; +import { HStack, VStack } from '../core/Stacks'; const buttonColors = [ 'primary', @@ -37,8 +50,62 @@ const icons: IconProps['icon'][] = [ ]; export function SettingsDesign() { + const themes = useThemes(); + + const [exportDir, setExportDir] = useLocalStorage('theme_export_dir', null); + + const saveThemes = async () => { + const dir = await open({ directory: true }); + if (!dir) return; + + const allThemesCSS = themes.themes.map(getThemeCSS).join('\n\n'); + const coreThemeCSS = [ + yaakDark, + catppuccinMacchiato, + rosePineDefault, + monokaiProDefault, + githubLight, + ] + .map(getThemeCSS) + .join('\n\n'); + + await invoke('cmd_write_file_dev', { + pathname: dir + '/themes-all.css', + contents: coreThemeCSS, + }); + await invoke('cmd_write_file_dev', { + pathname: dir + '/themes-slim.css', + contents: allThemesCSS, + }); + }; + return (
+ + {exportDir} + + + + + + { value={tab} addBorders label="Settings" - tabListClassName="h-md !-ml-1 mt-2" onChangeValue={setTab} tabs={tabs .filter((t) => t !== Tab.Design || isDev) diff --git a/src-web/components/core/Editor/Editor.css b/src-web/components/core/Editor/Editor.css index 41f13f64..341f2580 100644 --- a/src-web/components/core/Editor/Editor.css +++ b/src-web/components/core/Editor/Editor.css @@ -56,7 +56,7 @@ } } - .placeholder-widget { + .placeholder { /* Colors */ @apply bg-background text-fg-subtle border-background-highlight-secondary; @apply hover:border-background-highlight hover:text-fg hover:bg-background-highlight-secondary; @@ -150,7 +150,7 @@ .cm-editor .cm-foldPlaceholder { @apply px-2 border border-fg-subtler bg-background-highlight; - @apply hover:text-fg hover:border-fg-subtle; + @apply hover:text-fg hover:border-fg-subtle text-fg; @apply cursor-default !important; } diff --git a/src-web/components/core/Editor/twig/placeholder.ts b/src-web/components/core/Editor/twig/placeholder.ts index c4cb6f66..c044fc24 100644 --- a/src-web/components/core/Editor/twig/placeholder.ts +++ b/src-web/components/core/Editor/twig/placeholder.ts @@ -11,10 +11,8 @@ class PlaceholderWidget extends WidgetType { } toDOM() { const elt = document.createElement('span'); - elt.className = `x-theme-placeholder-widget placeholder-widget ${ - this.isExistingVariable - ? 'x-theme-placeholder-widget--primary' - : 'x-theme-placeholder-widget--danger' + elt.className = `x-theme-placeholder placeholder ${ + this.isExistingVariable ? 'x-theme-placeholder--primary' : 'x-theme-placeholder--danger' }`; elt.title = !this.isExistingVariable ? 'Variable not found in active environment' : ''; elt.textContent = this.name; diff --git a/src-web/components/core/Tabs/Tabs.tsx b/src-web/components/core/Tabs/Tabs.tsx index 69579b01..d8fe3237 100644 --- a/src-web/components/core/Tabs/Tabs.tsx +++ b/src-web/components/core/Tabs/Tabs.tsx @@ -74,6 +74,7 @@ export function Tabs({ aria-label={label} className={classNames( tabListClassName, + addBorders && '!-ml-1 h-md mt-2', 'flex items-center overflow-x-auto overflow-y-visible hide-scrollbars mt-1 mb-2', // Give space for button focus states within overflow boundary. '-ml-5 pl-3 pr-1 py-1', @@ -109,7 +110,6 @@ export function Tabs({ {option && 'shortLabel' in option ? option.shortLabel : option?.label ?? 'Unknown'} - {t.label} - ); } @@ -160,14 +159,3 @@ export const TabContent = memo(function TabContent({
); }); - -function TabAccent({ isActive, enabled }: { isActive: boolean; enabled: boolean }) { - return ( -
- ); -} diff --git a/src-web/hooks/usePreferredAppearance.ts b/src-web/hooks/usePreferredAppearance.ts new file mode 100644 index 00000000..a43902d7 --- /dev/null +++ b/src-web/hooks/usePreferredAppearance.ts @@ -0,0 +1,18 @@ +import { useEffect, useState } from 'react'; +import { + type Appearance, + getPreferredAppearance, + subscribeToPreferredAppearanceChange, +} from '../lib/theme/window'; + +export function usePreferredAppearance() { + const [preferredAppearance, setPreferredAppearance] = useState(); + + // Set appearance when preferred theme changes + useEffect(() => { + getPreferredAppearance().then(setPreferredAppearance); + return subscribeToPreferredAppearanceChange(setPreferredAppearance); + }, []); + + return preferredAppearance; +} diff --git a/src-web/hooks/useResolvedAppearance.ts b/src-web/hooks/useResolvedAppearance.ts index 8839c29b..1a31b253 100644 --- a/src-web/hooks/useResolvedAppearance.ts +++ b/src-web/hooks/useResolvedAppearance.ts @@ -1,17 +1,8 @@ -import { useEffect, useState } from 'react'; -import type { Appearance } from '../lib/theme/window'; -import { getPreferredAppearance, subscribeToPreferredAppearanceChange } from '../lib/theme/window'; +import { usePreferredAppearance } from './usePreferredAppearance'; import { useSettings } from './useSettings'; export function useResolvedAppearance() { - const [preferredAppearance, setPreferredAppearance] = useState( - getPreferredAppearance(), - ); - - // Set appearance when preferred theme changes - useEffect(() => { - return subscribeToPreferredAppearanceChange(setPreferredAppearance); - }, []); + const preferredAppearance = usePreferredAppearance(); const settings = useSettings(); const appearance = @@ -19,5 +10,7 @@ export function useResolvedAppearance() { ? preferredAppearance : settings.appearance; + console.log('HELLO', settings?.appearance, preferredAppearance); + return appearance; } diff --git a/src-web/lib/theme/themes/catppuccin.ts b/src-web/lib/theme/themes/catppuccin.ts index 6420c5dc..fa7b8b21 100644 --- a/src-web/lib/theme/themes/catppuccin.ts +++ b/src-web/lib/theme/themes/catppuccin.ts @@ -1,9 +1,9 @@ import { Color } from '../color'; import type { YaakTheme } from '../window'; -const catppuccinLatte: YaakTheme = { +export const catppuccinLatte: YaakTheme = { name: 'Catppuccin Latte', - id: 'catppuccin-light', + id: 'catppuccin-latte', background: new Color('#eff1f5', 'light'), foreground: new Color('#4c4f69', 'dark'), foregroundSubtle: new Color('#6c6f85', 'light'), @@ -31,9 +31,9 @@ const catppuccinLatte: YaakTheme = { }, }; -const catppuccinMacchiato: YaakTheme = { +export const catppuccinMacchiato: YaakTheme = { name: 'Catppuccin Macchiato', - id: 'catppuccin-Macchiato', + id: 'catppuccin-macchiato', background: new Color('#1e2030', 'dark'), foreground: new Color('#cad3f5', 'dark'), foregroundSubtle: new Color('#a5adcb', 'dark'), @@ -77,7 +77,7 @@ const catppuccinMacchiato: YaakTheme = { }, }; -const catppuccinFrappe: YaakTheme = { +export const catppuccinFrappe: YaakTheme = { name: 'Catppuccin Frappé', id: 'catppuccin-frappe', background: new Color('#292c3c', 'dark'), diff --git a/src-web/lib/theme/themes/github.ts b/src-web/lib/theme/themes/github.ts index fd06a57c..d79c0940 100644 --- a/src-web/lib/theme/themes/github.ts +++ b/src-web/lib/theme/themes/github.ts @@ -34,22 +34,22 @@ const githubDark: YaakTheme = { }, }; -const githubLight: YaakTheme = { +export const githubLight: YaakTheme = { id: 'github-light', name: 'GitHub', background: new Color('#ffffff', 'light'), - backgroundHighlight: new Color('#e8ebee', 'light'), - backgroundHighlightSecondary: new Color('#f6f8fa', 'light'), + backgroundHighlight: new Color('hsl(210,15%,92%)', 'light'), + backgroundHighlightSecondary: new Color('hsl(210,29%,94%)', 'light'), foreground: new Color('#1f2328', 'light'), foregroundSubtle: new Color('#636c76', 'light'), foregroundSubtler: new Color('#828d94', 'light'), colors: { primary: new Color('#8250df', 'light'), secondary: new Color('#6e7781', 'light'), - info: new Color('#0969da', 'light'), - success: new Color('#1a7f37', 'light'), - notice: new Color('#9a6700', 'light'), - warning: new Color('#bc4c00', 'light'), + info: new Color('hsl(212,92%,48%)', 'light'), + success: new Color('hsl(137,66%,32%)', 'light'), + notice: new Color('hsl(40,100%,40%)', 'light'), + warning: new Color('hsl(24,100%,44%)', 'light'), danger: new Color('#d1242f', 'light'), }, }; diff --git a/src-web/lib/theme/themes/monokai-pro.ts b/src-web/lib/theme/themes/monokai-pro.ts index 1c115657..12218d91 100644 --- a/src-web/lib/theme/themes/monokai-pro.ts +++ b/src-web/lib/theme/themes/monokai-pro.ts @@ -1,7 +1,7 @@ import { Color } from '../color'; import type { YaakTheme } from '../window'; -const monokaiProDefault: YaakTheme = { +export const monokaiProDefault: YaakTheme = { id: 'monokai-pro', name: 'Monokai Pro', background: new Color('#2d2a2e', 'dark'), diff --git a/src-web/lib/theme/themes/rose-pine.ts b/src-web/lib/theme/themes/rose-pine.ts index a3035982..83c2a429 100644 --- a/src-web/lib/theme/themes/rose-pine.ts +++ b/src-web/lib/theme/themes/rose-pine.ts @@ -1,7 +1,7 @@ import { Color } from '../color'; import type { YaakTheme } from '../window'; -const rosePineClassic: YaakTheme = { +export const rosePineDefault: YaakTheme = { id: 'rose-pine', name: 'Rosé Pine', background: new Color('#191724', 'dark'), @@ -105,4 +105,4 @@ const rosePineDawn: YaakTheme = { }, }; -export const rosePine = [rosePineClassic, rosePineDawn, rosePineMoon]; +export const rosePine = [rosePineDefault, rosePineDawn, rosePineMoon]; diff --git a/src-web/lib/theme/window.ts b/src-web/lib/theme/window.ts index 2b82a49c..13623102 100644 --- a/src-web/lib/theme/window.ts +++ b/src-web/lib/theme/window.ts @@ -180,7 +180,7 @@ function placeholderCSS(color: ColorName, colors?: Partial): string } return [ - variablesToCSS(`.x-theme-placeholder-widget--${color}`, placeholderColorVariables(cssColor)), + variablesToCSS(`.x-theme-placeholder--${color}`, placeholderColorVariables(cssColor)), ].join('\n\n'); } @@ -219,7 +219,8 @@ export function getThemeCSS(theme: YaakTheme): string { } catch (err) { console.error(err); } - return themeCSS; + + return [`/* ${theme.name} */`, `[data-theme="${theme.id}"] {`, themeCSS, '}'].join('\n'); } export function addThemeStylesToDocument(theme: YaakTheme) { @@ -230,20 +231,16 @@ export function addThemeStylesToDocument(theme: YaakTheme) { } styleEl.setAttribute('data-theme', theme.id); - styleEl.textContent = [ - `/* ${theme.name} */`, - `[data-theme="${theme.id}"] {`, - getThemeCSS(theme), - '}', - ].join('\n'); + styleEl.textContent = getThemeCSS(theme); } export function setThemeOnDocument(theme: YaakTheme) { document.documentElement.setAttribute('data-theme', theme.id); } -export function getPreferredAppearance(): Appearance { - return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; +export async function getPreferredAppearance(): Promise { + const a = await getCurrent().theme(); + return a ?? 'light'; } export function subscribeToPreferredAppearanceChange( @@ -252,7 +249,10 @@ export function subscribeToPreferredAppearanceChange( const container = { unsubscribe: () => {} }; getCurrent() - .onThemeChanged((t) => cb(t.payload)) + .onThemeChanged((t) => { + console.log('THEME CHANGED', t); + cb(t.payload); + }) .then((l) => { container.unsubscribe = l; });