From 70681a6d5174884bf92c8318ca172d285c2fad45 Mon Sep 17 00:00:00 2001 From: eythaann Date: Wed, 20 Nov 2024 12:15:40 -0500 Subject: [PATCH] refactor(tb): make toolbar more modular (part 1) --- capabilities/launcher.json | 2 +- capabilities/migrated.json | 8 +- capabilities/toolbar.json | 19 +++ capabilities/wall.json | 2 +- documentation/schemas/placeholder.schema.json | 16 ++- lib/src/handlers/events.ts | 2 + lib/src/handlers/invokers.ts | 5 + lib/src/handlers/mod.rs | 2 + lib/src/state/index.ts | 1 + lib/src/state/mod.rs | 4 + lib/src/state/placeholder.rs | 39 +++++-- lib/src/state/placeholder.ts | 6 +- lib/src/state/plugin.rs | 8 ++ lib/src/state/plugin.ts | 33 ++++++ lib/src/state/theme.ts | 2 +- lib/src/state/widget.rs | 6 + lib/src/utils/index.ts | 14 +++ src/apps/shared/styles.ts | 25 ++-- .../Notifications/infra/ArrivalPreview.tsx | 109 ++++++++++-------- .../modules/Notifications/infra/Module.tsx | 2 +- src/apps/toolbar/modules/item/infra/Inner.tsx | 2 +- src/apps/toolbar/modules/main/infra.tsx | 31 +++-- src/apps/toolbar/modules/shared/store/app.ts | 10 +- .../toolbar/modules/shared/store/domain.ts | 6 +- .../toolbar/modules/shared/store/infra.ts | 7 +- src/background/exposed.rs | 2 + src/background/seelen.rs | 2 + src/background/seelen_bar/mod.rs | 12 +- src/background/seelen_rofi/mod.rs | 4 +- src/background/seelen_wall/mod.rs | 4 +- src/background/seelen_weg/mod.rs | 8 +- src/background/seelen_wm_v2/instance.rs | 9 +- src/background/state/application/events.rs | 2 +- src/background/state/application/mod.rs | 55 ++++++++- src/background/state/application/plugins.rs | 41 +++++++ src/background/state/application/widgets.rs | 41 +++++++ src/background/state/infrastructure.rs | 14 ++- static/placeholders/default.yml | 105 +++-------------- static/placeholders/default_alter.yml | 15 +-- static/plugins/tb_default_bluethoot.yml | 7 ++ static/plugins/tb_default_date.yml | 6 + static/plugins/tb_default_focused_app.yml | 7 ++ .../plugins/tb_default_focused_app_title.yml | 7 ++ static/plugins/tb_default_media.yml | 17 +++ static/plugins/tb_default_network.yml | 15 +++ static/plugins/tb_default_notifications.yml | 10 ++ static/plugins/tb_default_power.yml | 26 +++++ static/plugins/tb_default_quick_settings.yml | 6 + static/plugins/tb_default_system_tray.yml | 6 + static/plugins/tb_default_user_folder.yml | 9 ++ static/widgets/demo.yml | 1 + 51 files changed, 552 insertions(+), 240 deletions(-) create mode 100644 capabilities/toolbar.json create mode 100644 lib/src/state/plugin.rs create mode 100644 lib/src/state/plugin.ts create mode 100644 lib/src/state/widget.rs create mode 100644 src/background/state/application/plugins.rs create mode 100644 src/background/state/application/widgets.rs create mode 100644 static/plugins/tb_default_bluethoot.yml create mode 100644 static/plugins/tb_default_date.yml create mode 100644 static/plugins/tb_default_focused_app.yml create mode 100644 static/plugins/tb_default_focused_app_title.yml create mode 100644 static/plugins/tb_default_media.yml create mode 100644 static/plugins/tb_default_network.yml create mode 100644 static/plugins/tb_default_notifications.yml create mode 100644 static/plugins/tb_default_power.yml create mode 100644 static/plugins/tb_default_quick_settings.yml create mode 100644 static/plugins/tb_default_system_tray.yml create mode 100644 static/plugins/tb_default_user_folder.yml create mode 100644 static/widgets/demo.yml diff --git a/capabilities/launcher.json b/capabilities/launcher.json index 13e9ca06..ddfc8625 100644 --- a/capabilities/launcher.json +++ b/capabilities/launcher.json @@ -2,7 +2,7 @@ "$schema": "../gen/schemas/windows-schema.json", "identifier": "launcher", "windows": [ - "seelen-launcher" + "seelen/launcher" ], "permissions": [ "log:default", diff --git a/capabilities/migrated.json b/capabilities/migrated.json index df89a4a7..19c1fd32 100644 --- a/capabilities/migrated.json +++ b/capabilities/migrated.json @@ -5,10 +5,8 @@ "local": true, "windows": [ "settings", - "seelenweg/*", - "updater", - "window-manager/*", - "fancy-toolbar/*" + "seelen/weg*", + "seelen/window-manager*" ], "permissions": [ "core:path:default", @@ -63,8 +61,6 @@ "log:allow-log", - "updater:default", - "shell:allow-open" ] } \ No newline at end of file diff --git a/capabilities/toolbar.json b/capabilities/toolbar.json new file mode 100644 index 00000000..0adfa017 --- /dev/null +++ b/capabilities/toolbar.json @@ -0,0 +1,19 @@ +{ + "$schema": "../gen/schemas/windows-schema.json", + "identifier": "toolbar", + "windows": [ + "seelen/fancy-toolbar*" + ], + "permissions": [ + "log:default", + "core:path:default", + "core:webview:default", + "core:event:default", + + "core:window:default", + "core:window:allow-show", + "core:window:allow-set-ignore-cursor-events", + + "dialog:default" + ] +} \ No newline at end of file diff --git a/capabilities/wall.json b/capabilities/wall.json index f1237d8a..f4989b49 100644 --- a/capabilities/wall.json +++ b/capabilities/wall.json @@ -4,7 +4,7 @@ "description": "permissions for wall", "local": true, "windows": [ - "seelen-wall" + "seelen/wall" ], "permissions": [ "log:default", diff --git a/documentation/schemas/placeholder.schema.json b/documentation/schemas/placeholder.schema.json index d1ab1f10..3148ce75 100644 --- a/documentation/schemas/placeholder.schema.json +++ b/documentation/schemas/placeholder.schema.json @@ -8,7 +8,7 @@ "default": [], "type": "array", "items": { - "$ref": "#/definitions/ToolbarItem" + "$ref": "#/definitions/ToolbarItem2" } }, "info": { @@ -30,7 +30,7 @@ "default": [], "type": "array", "items": { - "$ref": "#/definitions/ToolbarItem" + "$ref": "#/definitions/ToolbarItem2" } }, "right": { @@ -38,7 +38,7 @@ "default": [], "type": "array", "items": { - "$ref": "#/definitions/ToolbarItem" + "$ref": "#/definitions/ToolbarItem2" } } }, @@ -873,6 +873,16 @@ } ] }, + "ToolbarItem2": { + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/ToolbarItem" + } + ] + }, "WorkspaceToolbarItemMode": { "type": "string", "enum": [ diff --git a/lib/src/handlers/events.ts b/lib/src/handlers/events.ts index e2d9a0f0..3636f0dc 100644 --- a/lib/src/handlers/events.ts +++ b/lib/src/handlers/events.ts @@ -47,4 +47,6 @@ export enum SeelenEvent { StateSettingsByAppChanged = 'settings-by-app', StateHistoryChanged = 'history', StateIconPacksChanged = 'icon-packs', + StatePluginsChanged = 'plugins-changed', + StateWidgetsChanged = 'widgets-changed', } \ No newline at end of file diff --git a/lib/src/handlers/invokers.ts b/lib/src/handlers/invokers.ts index eb7ef25e..ecac0959 100644 --- a/lib/src/handlers/invokers.ts +++ b/lib/src/handlers/invokers.ts @@ -1,5 +1,7 @@ import { invoke as tauriInvoke, InvokeArgs, InvokeOptions } from '@tauri-apps/api/core'; +import { Plugin } from '../state/plugin'; + export enum SeelenCommand { // General Run = 'run', @@ -31,6 +33,8 @@ export enum SeelenCommand { StateGetWallpaper = 'state_get_wallpaper', StateSetWallpaper = 'state_set_wallpaper', StateGetHistory = 'state_get_history', + StateGetPlugins = 'state_get_plugins', + StateGetWidgets = 'state_get_widgets', // Media MediaPrev = 'media_prev', @@ -83,6 +87,7 @@ export enum SeelenCommand { type ReturnTypeByCommand = Record & { [SeelenCommand.CheckForUpdates]: boolean; [SeelenCommand.InstallLastAvailableUpdate]: never; + [SeelenCommand.StateGetPlugins]: Plugin[]; }; export type SeelenCommandReturn = ReturnTypeByCommand[T]; diff --git a/lib/src/handlers/mod.rs b/lib/src/handlers/mod.rs index 4f64a528..f9e0da6a 100644 --- a/lib/src/handlers/mod.rs +++ b/lib/src/handlers/mod.rs @@ -86,4 +86,6 @@ slu_events_declaration! { StateSettingsByAppChanged = "settings-by-app", StateHistoryChanged = "history", StateIconPacksChanged = "icon-packs", + StatePluginsChanged = "plugins-changed", + StateWidgetsChanged = "widgets-changed", } diff --git a/lib/src/state/index.ts b/lib/src/state/index.ts index 0c856cc3..2c925bb2 100644 --- a/lib/src/state/index.ts +++ b/lib/src/state/index.ts @@ -8,6 +8,7 @@ export * from './placeholder'; export * from './settings_by_app'; export * from './settings_by_monitor'; export * from './icon_pack'; +export * from './plugin'; export interface LauncherHistory { [x: string]: string[]; diff --git a/lib/src/state/mod.rs b/lib/src/state/mod.rs index 95c58c89..37b00b05 100644 --- a/lib/src/state/mod.rs +++ b/lib/src/state/mod.rs @@ -6,6 +6,8 @@ mod settings_by_monitor; mod theme; mod weg_items; mod wm_layout; +mod plugin; +mod widget; pub use icon_pack::*; pub use placeholder::*; @@ -15,6 +17,8 @@ pub use settings_by_monitor::*; pub use theme::*; pub use weg_items::*; pub use wm_layout::*; +pub use plugin::*; +pub use widget::*; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/lib/src/state/placeholder.rs b/lib/src/state/placeholder.rs index 77a40f24..b9458c04 100644 --- a/lib/src/state/placeholder.rs +++ b/lib/src/state/placeholder.rs @@ -315,6 +315,13 @@ impl ToolbarItem { } } +#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[serde(untagged)] +pub enum ToolbarItem2 { + PluginId(String), + Inline(ToolbarItem) +} + #[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)] #[serde(default, rename_all = "camelCase")] pub struct PlaceholderInfo { @@ -334,23 +341,33 @@ pub struct Placeholder { /// Metadata about the placeholder pub info: PlaceholderInfo, /// Items to be displayed in the toolbar - pub left: Vec, + pub left: Vec, /// Items to be displayed in the toolbar - pub center: Vec, + pub center: Vec, /// Items to be displayed in the toolbar - pub right: Vec, + pub right: Vec, } impl Placeholder { - fn sanitize_items(dict: &mut HashSet, items: Vec) -> Vec { + fn sanitize_items(dict: &mut HashSet, items: Vec) -> Vec { let mut result = Vec::new(); - for mut item in items { - if item.id().is_empty() { - item.set_id(uuid::Uuid::new_v4().to_string()); - } - if !dict.contains(&item.id()) { - dict.insert(item.id()); - result.push(item); + for item in items { + match item { + ToolbarItem2::PluginId(id) => { + if !dict.contains(&id) { + dict.insert(id.clone()); + result.push(ToolbarItem2::PluginId(id)); + } + } + ToolbarItem2::Inline(mut item) => { + if item.id().is_empty() { + item.set_id(uuid::Uuid::new_v4().to_string()); + } + if !dict.contains(&item.id()) { + dict.insert(item.id()); + result.push(ToolbarItem2::Inline(item)); + } + } } } result diff --git a/lib/src/state/placeholder.ts b/lib/src/state/placeholder.ts index 63fb2561..1477c909 100644 --- a/lib/src/state/placeholder.ts +++ b/lib/src/state/placeholder.ts @@ -111,7 +111,7 @@ export interface CreatorInfo { export interface Placeholder { info: CreatorInfo; - left: ToolbarModule[]; - center: ToolbarModule[]; - right: ToolbarModule[]; + left: (string | ToolbarModule)[]; + center: (string | ToolbarModule)[]; + right: (string | ToolbarModule)[]; } diff --git a/lib/src/state/plugin.rs b/lib/src/state/plugin.rs new file mode 100644 index 00000000..80966ea0 --- /dev/null +++ b/lib/src/state/plugin.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Plugin { + pub id: String, + pub target: String, + pub plugin: serde_yaml::Value, +} \ No newline at end of file diff --git a/lib/src/state/plugin.ts b/lib/src/state/plugin.ts new file mode 100644 index 00000000..99005a47 --- /dev/null +++ b/lib/src/state/plugin.ts @@ -0,0 +1,33 @@ +import { listen, UnlistenFn } from '@tauri-apps/api/event'; + +import { invoke, SeelenCommand, SeelenEvent } from '../handlers'; +import { getCurrentWidget } from '../utils'; + +export class Plugin { + id: string = ''; + target: string = ''; + plugin: any = {}; +} + +export class PluginList { + private constructor(private inner: Plugin[]) {} + + static async getAsync(): Promise { + return new PluginList(await invoke(SeelenCommand.StateGetPlugins)); + } + + static async onChange(cb: (value: PluginList) => void): Promise { + return listen(SeelenEvent.StatePluginsChanged, (event) => { + cb(new PluginList(event.payload)); + }); + } + + all(): Plugin[] { + return this.inner; + } + + forCurrentWidget(): Plugin[] { + let target = getCurrentWidget().id; + return this.inner.filter((plugin) => plugin.target === target); + } +} diff --git a/lib/src/state/theme.ts b/lib/src/state/theme.ts index a6072b96..dc4ed8d7 100644 --- a/lib/src/state/theme.ts +++ b/lib/src/state/theme.ts @@ -28,5 +28,5 @@ export interface Theme { /** Metadata about the theme */ info: ThemeInfo; /** Css Styles of the theme */ - styles: ThemeCssByApp; + styles: ThemeCssByApp & Record; } diff --git a/lib/src/state/widget.rs b/lib/src/state/widget.rs new file mode 100644 index 00000000..e2c7b75a --- /dev/null +++ b/lib/src/state/widget.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Widget { + pub id: String, +} diff --git a/lib/src/utils/index.ts b/lib/src/utils/index.ts index 101f8f29..9401ee8e 100644 --- a/lib/src/utils/index.ts +++ b/lib/src/utils/index.ts @@ -1,3 +1,5 @@ +import { getCurrentWindow } from '@tauri-apps/api/window'; + export * from './hooks'; export * from './layered_hitbox'; @@ -46,3 +48,15 @@ export function disableWebviewShortcutsAndContextMenu() { window.addEventListener('drop', (e) => e.preventDefault()); window.addEventListener('dragover', (e) => e.preventDefault()); } + +// label schema: user/resource__query__monitor:display5 +export function getCurrentWidget() { + const { label } = getCurrentWindow(); + const parsedLabel = label.replace('__query__', '?').replace(':', '='); + const query = new URLSearchParams(parsedLabel); + return { + id: `@${parsedLabel.split('?')[0]}`, + label, + attachedMonitor: query.get('monitor'), + }; +} \ No newline at end of file diff --git a/src/apps/shared/styles.ts b/src/apps/shared/styles.ts index 898f5584..06027c3a 100644 --- a/src/apps/shared/styles.ts +++ b/src/apps/shared/styles.ts @@ -1,7 +1,6 @@ import { listen } from '@tauri-apps/api/event'; -import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'; import { useEffect, useState } from 'react'; -import { Settings, Theme, UIColors } from 'seelen-core'; +import { getCurrentWidget, Settings, Theme, UIColors } from 'seelen-core'; import { UserSettingsLoader } from '../settings/modules/shared/store/storeApi'; @@ -45,11 +44,11 @@ export function useDarkMode() { } const KeyByLabel: Record = { - 'fancy-toolbar': 'toolbar', - seelenweg: 'weg', - 'window-manager': 'wm', - 'seelen-launcher': 'launcher', - 'seelen-wall': 'wall', + '@seelen/fancy-toolbar': 'toolbar', + '@seelen/weg': 'weg', + '@seelen/window-manager': 'wm', + '@seelen/launcher': 'launcher', + '@seelen/wall': 'wall', }; async function loadThemes(allThemes: Theme[], selected: string[]) { @@ -59,20 +58,16 @@ async function loadThemes(allThemes: Theme[], selected: string[]) { return selected.indexOf(a.info.filename) - selected.indexOf(b.info.filename); }); - const webviewId = getCurrentWebviewWindow().label; - const [label, _monitor] = webviewId.split('/'); - if (!label) { - return; - } + const widget = getCurrentWidget(); - const theme_key = KeyByLabel[label] as keyof Theme['styles'] | undefined; + const theme_key = KeyByLabel[widget.id] || widget.id; if (!theme_key) { return; } - document.getElementById(webviewId)?.remove(); + document.getElementById(widget.label)?.remove(); let element = document.createElement('style'); - element.id = webviewId; + element.id = widget.label; element.textContent = ''; for (const theme of themes) { diff --git a/src/apps/toolbar/modules/Notifications/infra/ArrivalPreview.tsx b/src/apps/toolbar/modules/Notifications/infra/ArrivalPreview.tsx index dff4cd64..95047abd 100644 --- a/src/apps/toolbar/modules/Notifications/infra/ArrivalPreview.tsx +++ b/src/apps/toolbar/modules/Notifications/infra/ArrivalPreview.tsx @@ -1,4 +1,3 @@ -/* eslint-disable @stylistic/indent */ import { invoke } from '@tauri-apps/api/core'; import { Button } from 'antd'; import { AnimatePresence, motion } from 'framer-motion'; @@ -11,6 +10,8 @@ import { BackgroundByLayersV2 } from '../../../../seelenweg/components/Backgroun import { Selectors } from '../../shared/store/app'; +import { AppNotification } from '../../shared/store/domain'; + import { Icon } from '../../../../shared/components/Icon'; // Difference between Windows epoch (1601) and Unix epoch (1970) in milliseconds @@ -23,66 +24,76 @@ function WindowsDateFileTimeToDate(fileTime: bigint) { export function ArrivalPreview() { const notifications = useSelector(Selectors.notifications); - const [ currentNotificationPreviewSet, setCurrentNotificationPreviewSet ] = useState(false); + const [currentNotificationPreviewSet, setCurrentNotificationPreviewSet] = useState([]); - useTimeout(() => { - setCurrentNotificationPreviewSet(notifications.filter((notification) => { - const arrivalDate = WindowsDateFileTimeToDate(BigInt(notification.date)); + useTimeout( + () => { + setCurrentNotificationPreviewSet( + notifications.filter((notification) => { + const arrivalDate = WindowsDateFileTimeToDate(BigInt(notification.date)); - return moment(Date.now()).diff(arrivalDate, 'seconds') < 10; - })); - }, notificationArrivalViewTime, [currentNotificationPreviewSet]); + return moment(Date.now()).diff(arrivalDate, 'seconds') < 10; + }), + ); + }, + notificationArrivalViewTime, + [currentNotificationPreviewSet], + ); useEffect(() => { - setCurrentNotificationPreviewSet(notifications.filter((notification) => { - const arrivalDate = WindowsDateFileTimeToDate(BigInt(notification.date)); + setCurrentNotificationPreviewSet( + notifications.filter((notification) => { + const arrivalDate = WindowsDateFileTimeToDate(BigInt(notification.date)); - return moment(Date.now()).diff(arrivalDate, 'seconds') < 10; - })); + return moment(Date.now()).diff(arrivalDate, 'seconds') < 10; + }), + ); }, [notifications]); return ( - { currentNotificationPreviewSet && - currentNotificationPreviewSet.map((notification) => { - return ( - -
-
- -
{notification.app_name}
- - -
- {moment(WindowsDateFileTimeToDate(BigInt(notification.date))).fromNow()} -
+ {currentNotificationPreviewSet && + currentNotificationPreviewSet.map((notification) => { + return ( + +
+
+ +
{notification.app_name}
+ - +
+ {moment(WindowsDateFileTimeToDate(BigInt(notification.date))).fromNow()}
- -
-
-

{notification.body[0]}

- {notification.body.slice(1).map((body, idx) => ( -

{body}

- ))}
- - ); - })} + +
+
+

{notification.body[0]}

+ {notification.body.slice(1).map((body, idx) => ( +

{body}

+ ))} +
+
+ ); + })} ); diff --git a/src/apps/toolbar/modules/Notifications/infra/Module.tsx b/src/apps/toolbar/modules/Notifications/infra/Module.tsx index a354351e..4470c322 100644 --- a/src/apps/toolbar/modules/Notifications/infra/Module.tsx +++ b/src/apps/toolbar/modules/Notifications/infra/Module.tsx @@ -1,6 +1,6 @@ import { emit } from '@tauri-apps/api/event'; import { Popover } from 'antd'; -import React, { useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import { NotificationsTM, useWindowFocusChange } from 'seelen-core'; diff --git a/src/apps/toolbar/modules/item/infra/Inner.tsx b/src/apps/toolbar/modules/item/infra/Inner.tsx index dbc1e738..19ffb9d9 100644 --- a/src/apps/toolbar/modules/item/infra/Inner.tsx +++ b/src/apps/toolbar/modules/item/infra/Inner.tsx @@ -216,6 +216,7 @@ export function InnerItem(props: InnerItemProps) { diff --git a/src/apps/toolbar/modules/main/infra.tsx b/src/apps/toolbar/modules/main/infra.tsx index a9be0e28..770e7cda 100644 --- a/src/apps/toolbar/modules/main/infra.tsx +++ b/src/apps/toolbar/modules/main/infra.tsx @@ -2,7 +2,7 @@ import { Reorder, useForceUpdate } from 'framer-motion'; import { debounce } from 'lodash'; import { JSXElementConstructor, useCallback, useLayoutEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { HideMode, useWindowFocusChange } from 'seelen-core'; +import { HideMode, Plugin, useWindowFocusChange } from 'seelen-core'; import { Placeholder, ToolbarModule, ToolbarModuleType } from 'seelen-core'; import { BackgroundByLayersV2 } from '../../../seelenweg/components/BackgroundByLayers/infra'; @@ -22,7 +22,7 @@ import { cx } from '../../../shared/styles'; import { TrayModule } from '../Tray'; import { WorkspacesModule } from '../Workspaces'; -const modulesByType: Record> = { +const modulesByType: Record> = { [ToolbarModuleType.Text]: Item, [ToolbarModuleType.Generic]: GenericItem, [ToolbarModuleType.Date]: DateModule, @@ -43,18 +43,33 @@ interface Props { const DividerStart = 'CenterStart'; const DividerEnd = 'CenterEnd'; -function componentByModule(module: ToolbarModule, idx: number) { +function componentByModule(plugins: Plugin[], item: string | ToolbarModule) { + let module: ToolbarModule; + + if (typeof item === 'string') { + module = plugins.find((p) => p.id === item)?.plugin; + if (!module) { + return null; + } + module = { ...module }; + module.id = item; + (module as any).__value__ = item; + } else { + module = item; + } + let Component = modulesByType[module.type]; if (!Component) { return null; } - return ; + return ; } export function ToolBar({ structure }: Props) { const [isAppFocused, setAppFocus] = useState(false); const [delayed, setDelayed] = useState(false); + const plugins = useSelector(Selectors.plugins); const isOverlaped = useSelector(Selectors.isOverlaped); const hideMode = useSelector(Selectors.settings.hideMode); @@ -131,13 +146,15 @@ export function ToolBar({ structure }: Props) { >
- {structure.left.map(componentByModule)} + {structure.left.map(componentByModule.bind(null, plugins))}
-
{structure.center.map(componentByModule)}
+
+ {structure.center.map(componentByModule.bind(null, plugins))} +
- {structure.right.map(componentByModule)} + {structure.right.map(componentByModule.bind(null, plugins))}
); diff --git a/src/apps/toolbar/modules/shared/store/app.ts b/src/apps/toolbar/modules/shared/store/app.ts index f085de8e..df5219b3 100644 --- a/src/apps/toolbar/modules/shared/store/app.ts +++ b/src/apps/toolbar/modules/shared/store/app.ts @@ -8,10 +8,11 @@ import { StateBuilder } from '../../../../shared/StateBuilder'; const initialState: RootState = { version: 0, + placeholder: null, + plugins: [], dateFormat: '', isOverlaped: false, focused: null, - placeholder: null, settings: new FancyToolbarSettings(), env: {}, // default values of https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-system_power_status @@ -65,9 +66,10 @@ export const RootSlice = createSlice({ removeItem(state, action: PayloadAction) { let id = action.payload; if (state.placeholder) { - state.placeholder.left = state.placeholder.left.filter((d) => d.id !== id); - state.placeholder.center = state.placeholder.center.filter((d) => d.id !== id); - state.placeholder.right = state.placeholder.right.filter((d) => d.id !== id); + let filter = (d: any) => d !== id && d.id !== id; + state.placeholder.left = state.placeholder.left.filter(filter); + state.placeholder.center = state.placeholder.center.filter(filter); + state.placeholder.right = state.placeholder.right.filter(filter); } }, }, diff --git a/src/apps/toolbar/modules/shared/store/domain.ts b/src/apps/toolbar/modules/shared/store/domain.ts index 0b1fc899..6d5e255c 100644 --- a/src/apps/toolbar/modules/shared/store/domain.ts +++ b/src/apps/toolbar/modules/shared/store/domain.ts @@ -1,6 +1,6 @@ import { SoftOpaque } from 'readable-types'; import { FancyToolbarSettings, Settings } from 'seelen-core'; -import { Placeholder } from 'seelen-core'; +import { Placeholder, Plugin } from 'seelen-core'; import { WlanBssEntry } from '../../network/domain'; @@ -112,9 +112,11 @@ export interface Workspace { export interface RootState extends IRootState, Pick { version: number; + placeholder: Placeholder | null; + plugins: Plugin[]; + isOverlaped: boolean; focused: FocusedApp | null; - placeholder: Placeholder | null; env: Record; powerStatus: PowerStatus; batteries: Battery[]; diff --git a/src/apps/toolbar/modules/shared/store/infra.ts b/src/apps/toolbar/modules/shared/store/infra.ts index 3d9feb5e..e3e001d8 100644 --- a/src/apps/toolbar/modules/shared/store/infra.ts +++ b/src/apps/toolbar/modules/shared/store/infra.ts @@ -2,7 +2,7 @@ import { configureStore } from '@reduxjs/toolkit'; import { listen as listenGlobal } from '@tauri-apps/api/event'; import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow'; import { debounce, throttle } from 'lodash'; -import { SeelenEvent, UIColors } from 'seelen-core'; +import { PluginList, SeelenEvent, UIColors } from 'seelen-core'; import { FancyToolbarSettings } from 'seelen-core'; import { IsSavingCustom } from '../../main/application'; @@ -129,6 +129,11 @@ export async function registerStoreEvents() { setPlaceholder(userSettings); }); + store.dispatch(RootActions.setPlugins((await PluginList.getAsync()).forCurrentWidget())); + await PluginList.onChange((list) => { + store.dispatch(RootActions.setPlugins(list.forCurrentWidget())); + }); + await initUIColors(); await StartThemingTool(); await view.emitTo(view.label, 'store-events-ready'); diff --git a/src/background/exposed.rs b/src/background/exposed.rs index 93b65cbc..3d1b3bb2 100644 --- a/src/background/exposed.rs +++ b/src/background/exposed.rs @@ -189,6 +189,8 @@ pub fn register_invoke_handler(app_builder: Builder) -> Builder { state_get_wallpaper, state_set_wallpaper, state_get_history, + state_get_plugins, + state_get_widgets, // Media media_prev, media_toggle_play_pause, diff --git a/src/background/seelen.rs b/src/background/seelen.rs index 2b4ed8c5..b7ac7a5f 100644 --- a/src/background/seelen.rs +++ b/src/background/seelen.rs @@ -283,6 +283,8 @@ impl Seelen { create_if_needed("layouts")?; create_if_needed("icons/system")?; create_if_needed("wallpapers")?; + create_if_needed("plugins")?; + create_if_needed("widgets")?; Ok(()) } diff --git a/src/background/seelen_bar/mod.rs b/src/background/seelen_bar/mod.rs index 556e1f39..6c3ed814 100644 --- a/src/background/seelen_bar/mod.rs +++ b/src/background/seelen_bar/mod.rs @@ -42,10 +42,9 @@ impl Drop for FancyToolbar { } impl FancyToolbar { - pub fn new(postfix: &str) -> Result { - log::info!("Creating {}/{}", Self::TARGET, postfix); + pub fn new(monitor: &str) -> Result { Ok(Self { - window: Self::create_window(postfix)?, + window: Self::create_window(monitor)?, last_focus: None, theoretical_rect: RECT::default(), overlaped: false, @@ -111,7 +110,6 @@ impl FancyToolbar { // statics impl FancyToolbar { pub const TITLE: &'static str = "Seelen Fancy Toolbar"; - const TARGET: &'static str = "fancy-toolbar"; /// Work area no works fine on multiple monitors /// so we use this functions that only takes the toolbar in account @@ -160,10 +158,10 @@ impl FancyToolbar { Ok(()) } - fn create_window(postfix: &str) -> Result { + fn create_window(monitor: &str) -> Result { let manager = get_app_handle(); - - let label = format!("{}/{}", Self::TARGET, postfix); + let label = format!("seelen/fancy-toolbar__query__monitor:{}", monitor); + log::info!("Creating @{}", label); let window = tauri::WebviewWindowBuilder::new( manager, label, diff --git a/src/background/seelen_rofi/mod.rs b/src/background/seelen_rofi/mod.rs index 81fe1c1e..c017b789 100644 --- a/src/background/seelen_rofi/mod.rs +++ b/src/background/seelen_rofi/mod.rs @@ -35,10 +35,10 @@ impl Drop for SeelenRofi { impl SeelenRofi { pub const TITLE: &str = "Seelen App Launcher"; - pub const TARGET: &str = "seelen-launcher"; + pub const TARGET: &str = "seelen/launcher"; pub fn new() -> Result { - log::info!("Creating {}", Self::TARGET); + log::info!("Creating @{}", Self::TARGET); Ok(Self { // apps should be loaded first because it takes a long time on start and its needed by webview apps: Self::load_apps()?, diff --git a/src/background/seelen_wall/mod.rs b/src/background/seelen_wall/mod.rs index 9198fd36..9013a994 100644 --- a/src/background/seelen_wall/mod.rs +++ b/src/background/seelen_wall/mod.rs @@ -29,10 +29,10 @@ impl Drop for SeelenWall { impl SeelenWall { pub const TITLE: &str = "Seelen Wall"; - const TARGET: &str = "seelen-wall"; + const TARGET: &str = "seelen/wall"; pub fn new() -> Result { - log::info!("Creating {}", Self::TARGET); + log::info!("Creating @{}", Self::TARGET); Ok(Self { window: Self::create_window()?, }) diff --git a/src/background/seelen_weg/mod.rs b/src/background/seelen_weg/mod.rs index 8a2ad5be..4ec3df7c 100644 --- a/src/background/seelen_weg/mod.rs +++ b/src/background/seelen_weg/mod.rs @@ -230,13 +230,11 @@ impl SeelenWeg { // INSTANCE impl SeelenWeg { pub fn new(postfix: &str) -> Result { - log::info!("Creating {}/{}", Self::TARGET, postfix); let weg = Self { window: Self::create_window(postfix)?, overlaped: false, theoretical_rect: RECT::default(), }; - Ok(weg) } @@ -339,14 +337,16 @@ impl SeelenWeg { impl SeelenWeg { pub const TITLE: &'static str = "SeelenWeg"; - const TARGET: &'static str = "seelenweg"; + const TARGET: &'static str = "seelen/weg"; fn create_window(postfix: &str) -> Result { let manager = get_app_handle(); + let label = format!("{}__query__monitor:{}", Self::TARGET, postfix); + log::info!("Creating @{}", label); let window = tauri::WebviewWindowBuilder::new( manager, - format!("{}/{}", Self::TARGET, postfix), + label, tauri::WebviewUrl::App("seelenweg/index.html".into()), ) .title(Self::TITLE) diff --git a/src/background/seelen_wm_v2/instance.rs b/src/background/seelen_wm_v2/instance.rs index d5351830..df5962c1 100644 --- a/src/background/seelen_wm_v2/instance.rs +++ b/src/background/seelen_wm_v2/instance.rs @@ -23,19 +23,20 @@ impl Drop for WindowManagerV2 { impl WindowManagerV2 { pub const TITLE: &'static str = "Seelen Window Manager"; - pub const TARGET: &'static str = "window-manager"; + pub const TARGET: &'static str = "seelen/window-manager"; pub fn new(monitor_id: &str) -> Result { - log::info!("Creating Tiling Windows Manager"); Ok(Self { window: Self::create_window(monitor_id)?, }) } fn create_window(monitor_id: &str) -> Result { + let label = format!("{}__query__monitor:{}", Self::TARGET, monitor_id); + log::info!("Creating @{}", label); let window = tauri::WebviewWindowBuilder::new( get_app_handle(), - format!("{}/{}", Self::TARGET, monitor_id), + label, tauri::WebviewUrl::App("seelen_wm_v2/index.html".into()), ) .title(Self::TITLE) @@ -65,7 +66,7 @@ impl WindowManagerV2 { let workspace_id = get_vd_manager().get_current()?.id(); let w = m.get_workspace_mut(&workspace_id); app.emit_to( - format!("{}/{}", Self::TARGET, monitor_id), + format!("{}__query__monitor:{}", Self::TARGET, monitor_id), SeelenEvent::WMSetLayout, w.get_root_node(), )?; diff --git a/src/background/state/application/events.rs b/src/background/state/application/events.rs index 901a6e93..32052283 100644 --- a/src/background/state/application/events.rs +++ b/src/background/state/application/events.rs @@ -55,7 +55,7 @@ impl FullState { } pub(super) fn emit_history(&self) -> Result<()> { - get_app_handle().emit(SeelenEvent::StateHistoryChanged, self.history())?; + get_app_handle().emit(SeelenEvent::StateHistoryChanged, self.launcher_history())?; Ok(()) } diff --git a/src/background/state/application/mod.rs b/src/background/state/application/mod.rs index 62ea31e6..61e2390d 100644 --- a/src/background/state/application/mod.rs +++ b/src/background/state/application/mod.rs @@ -1,6 +1,8 @@ mod apps_config; mod events; mod icons; +mod plugins; +mod widgets; use arc_swap::ArcSwap; use getset::Getters; @@ -12,7 +14,9 @@ use notify_debouncer_full::{ DebounceEventResult, DebouncedEvent, Debouncer, FileIdMap, }; use parking_lot::Mutex; -use seelen_core::state::{IconPack, VirtualDesktopStrategy, WegItems, WindowManagerLayout}; +use seelen_core::state::{ + IconPack, Plugin, VirtualDesktopStrategy, WegItems, Widget, WindowManagerLayout, +}; use std::{ collections::{HashMap, VecDeque}, fs::{File, OpenOptions}, @@ -72,7 +76,10 @@ pub struct FullState { pub placeholders: HashMap, pub layouts: HashMap, pub weg_items: Arc>, - pub history: LauncherHistory, + pub launcher_history: LauncherHistory, + + pub plugins: HashMap, + pub widgets: HashMap, } unsafe impl Sync for FullState {} @@ -92,7 +99,9 @@ impl FullState { placeholders: HashMap::new(), layouts: HashMap::new(), weg_items: Arc::new(Mutex::new(WegItems::default())), - history: HashMap::new(), + launcher_history: HashMap::new(), + plugins: HashMap::new(), + widgets: HashMap::new(), }; manager.load_all()?; manager.start_listeners()?; @@ -130,6 +139,12 @@ impl FullState { let user_app_configs = self.data_dir.join("applications.yml"); let bundled_app_configs = self.resources_dir.join("static/apps_templates"); + let user_plugins = self.data_dir.join("plugins"); + let bundled_plugins = self.resources_dir.join("static/plugins"); + + let user_widgets = self.data_dir.join("widgets"); + let bundled_widgets = self.resources_dir.join("static/widgets"); + if event.paths.contains(&self.icon_packs_folder()) { log::info!("Icons Packs changed"); self.load_icons_packs()?; @@ -202,6 +217,28 @@ impl FullState { self.emit_settings_by_app()?; } + if event + .paths + .iter() + .any(|p| p.starts_with(&user_plugins) || p.starts_with(&bundled_plugins)) + { + log::info!("Plugins changed"); + self.load_plugins()?; + self.store_cloned(); + self.emit_plugins()?; + } + + if event + .paths + .iter() + .any(|p| p.starts_with(&user_widgets) || p.starts_with(&bundled_widgets)) + { + log::info!("Widgets changed"); + self.load_widgets()?; + self.store_cloned(); + self.emit_widgets()?; + } + Ok(()) } @@ -233,14 +270,18 @@ impl FullState { self.data_dir.join("applications.yml"), self.data_dir.join("history"), // resources - self.data_dir.join("themes"), self.icon_packs_folder(), + self.data_dir.join("themes"), self.data_dir.join("placeholders"), self.data_dir.join("layouts"), + self.data_dir.join("plugins"), + self.data_dir.join("widgets"), self.resources_dir.join("static/themes"), self.resources_dir.join("static/placeholders"), self.resources_dir.join("static/layouts"), self.resources_dir.join("static/apps_templates"), + self.resources_dir.join("static/plugins"), + self.resources_dir.join("static/widgets"), ]; for path in paths { @@ -485,9 +526,9 @@ impl FullState { fn load_history(&mut self) -> Result<()> { let history_path = self.data_dir.join("history"); if history_path.exists() { - self.history = serde_yaml::from_str(&std::fs::read_to_string(&history_path)?)?; + self.launcher_history = serde_yaml::from_str(&std::fs::read_to_string(&history_path)?)?; } else { - std::fs::write(history_path, serde_yaml::to_string(&self.history)?)?; + std::fs::write(history_path, serde_yaml::to_string(&self.launcher_history)?)?; } Ok(()) } @@ -501,6 +542,8 @@ impl FullState { self.load_layouts()?; self.load_settings_by_app()?; self.load_history()?; + self.load_plugins()?; + self.load_widgets()?; Ok(()) } diff --git a/src/background/state/application/plugins.rs b/src/background/state/application/plugins.rs new file mode 100644 index 00000000..5dca9b6c --- /dev/null +++ b/src/background/state/application/plugins.rs @@ -0,0 +1,41 @@ +use std::path::PathBuf; + +use seelen_core::{handlers::SeelenEvent, state::Plugin}; +use tauri::Emitter; + +use crate::{error_handler::Result, seelen::get_app_handle}; + +use super::FullState; + +impl FullState { + pub(super) fn emit_plugins(&self) -> Result<()> { + get_app_handle().emit(SeelenEvent::StatePluginsChanged, &self.plugins)?; + Ok(()) + } + + fn load_plugin_from_file(path: PathBuf) -> Result { + Ok(serde_yaml::from_str(&std::fs::read_to_string(&path)?)?) + } + + pub(super) fn load_plugins(&mut self) -> Result<()> { + let user_path = self.data_dir.join("plugins"); + let bundled_path = self.resources_dir.join("static/plugins"); + + let entries = std::fs::read_dir(&bundled_path)?.chain(std::fs::read_dir(&user_path)?); + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + continue; + } + match Self::load_plugin_from_file(path) { + Ok(plugin) => { + self.plugins.insert(plugin.id.clone(), plugin); + } + Err(e) => { + log::error!("Failed to load plugin: {}", e); + } + } + } + Ok(()) + } +} diff --git a/src/background/state/application/widgets.rs b/src/background/state/application/widgets.rs new file mode 100644 index 00000000..eea187d3 --- /dev/null +++ b/src/background/state/application/widgets.rs @@ -0,0 +1,41 @@ +use std::path::PathBuf; + +use seelen_core::{handlers::SeelenEvent, state::Widget}; +use tauri::Emitter; + +use crate::{error_handler::Result, seelen::get_app_handle}; + +use super::FullState; + +impl FullState { + pub(super) fn emit_widgets(&self) -> Result<()> { + get_app_handle().emit(SeelenEvent::StateWidgetsChanged, &self.plugins)?; + Ok(()) + } + + fn load_widget_from_file(path: PathBuf) -> Result { + Ok(serde_yaml::from_str(&std::fs::read_to_string(&path)?)?) + } + + pub(super) fn load_widgets(&mut self) -> Result<()> { + let user_path = self.data_dir.join("widgets"); + let bundled_path = self.resources_dir.join("static/widgets"); + + let entries = std::fs::read_dir(&bundled_path)?.chain(std::fs::read_dir(&user_path)?); + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + continue; + } + match Self::load_widget_from_file(path) { + Ok(widget) => { + self.widgets.insert(widget.id.clone(), widget); + } + Err(e) => { + log::error!("Failed to load widget: {}", e); + } + } + } + Ok(()) + } +} diff --git a/src/background/state/infrastructure.rs b/src/background/state/infrastructure.rs index b1b24218..4c473183 100644 --- a/src/background/state/infrastructure.rs +++ b/src/background/state/infrastructure.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use itertools::Itertools; -use seelen_core::state::{WegItems, WindowManagerLayout}; +use seelen_core::state::{Plugin, WegItems, Widget, WindowManagerLayout}; use crate::{error_handler::Result, trace_lock, windows_api::WindowsApi}; @@ -39,7 +39,7 @@ pub fn state_get_weg_items() -> WegItems { #[tauri::command(async)] pub fn state_get_history() -> LauncherHistory { - FULL_STATE.load().history().clone() + FULL_STATE.load().launcher_history().clone() } #[tauri::command(async)] @@ -72,3 +72,13 @@ pub fn state_get_wallpaper() -> Result { pub fn state_set_wallpaper(path: String) -> Result<()> { WindowsApi::set_wallpaper(path) } + +#[tauri::command(async)] +pub fn state_get_plugins() -> Vec { + FULL_STATE.load().plugins().values().cloned().collect_vec() +} + +#[tauri::command(async)] +pub fn state_get_widgets() -> Vec { + FULL_STATE.load().widgets().values().cloned().collect_vec() +} diff --git a/static/placeholders/default.yml b/static/placeholders/default.yml index 3c2b670f..4708473e 100644 --- a/static/placeholders/default.yml +++ b/static/placeholders/default.yml @@ -3,106 +3,27 @@ info: author: eythaann, description: Default toolbar layout good for many devices. left: - - type: generic - template: concat("@", env.USERNAME) - onClickV2: open(env.USERPROFILE) - tooltip: t("placeholder.open_user_folder") - style: - flexShrink: 0 + - "@default/user-folder" - - type: generic - template: '"|"' + - type: text + template: '"//"' - - type: generic - template: concat(imgFromExe(window.exe), " ", window.name) - style: - flexShrink: 0 + - "@default/focused-app" - type: generic template: > window.title ? "-" : "" - - type: generic - template: window.title - style: - flexShrink: 2 + - "@default/focused-app-title" center: - - type: date - each: minute - format: ddd D MMM, hh:mm A - template: date + - "@default/date" right: - - type: tray - template: icon.BsThreeDots - tooltip: t("placeholder.open_system_tray") - - - type: device - template: icon.TbBluetoothConnected - onClick: open -> "ms-settings:connecteddevices" - tooltip: t("placeholder.bluetooth_devices") - - - type: network - withWlanSelector: true - tooltip: >- - online ? t("placeholder.ethernet_connected") : t("placeholder.ethernet_disconnected") - template: >- - online - ? ( - unequal(usingInterface, null) and equalText(usingInterface.type, "IEEE80211") - ? getIcon("FaWifi", 14) - : icon.FaComputer - ) - : icon.TbWorldCancel - - - type: media - withMediaControls: true - template: >- - isMuted - ? icon.IoVolumeMuteOutline - : volume >= 0.66 - ? icon.IoVolumeHighOutline - : volume >= 0.33 - ? icon.IoVolumeMediumOutline - : volume != 0 - ? icon.IoVolumeLowOutline - : icon.IoVolumeOffOutline - tooltip: >- - concat(t("placeholder.volume"), ": ", string(round(volume * 100)), "%") - - - type: power - tooltip: >- - concat(string(battery.percentage), t("placeholder.battery_remaining"), battery.smartCharging ? t("placeholder.smart_charge") : "") - template: >- - concat( - string(equalText(battery.state, "charging") ? concat(getIcon("MdOutlineElectricBolt", 12), " ") : ""), - string(battery.smartCharging ? concat(getIcon("FaHeart", 12), " ") : ""), - string( - battery.percentage > 90 - ? icon.PiBatteryFullFill - : battery.percentage > 66 - ? icon.PiBatteryHighFill - : battery.percentage > 33 - ? icon.PiBatteryMediumFill - : battery.percentage > 5 - ? icon.PiBatteryLowFill - : icon.PiBatteryWarning - ), - " ", - string(battery.percentage), - "%" - ) - onClick: open -> "ms-settings:powersleep" - - - type: notifications - template: >- - count > 0 ? icon.MdNotificationsActive : icon.MdOutlineNotifications - badge: >- - count > 0 ? count : "" - tooltip: >- - concat(t("placeholder.notifications"), ": ", string(count)) - - - type: settings - template: icon.LuSettings2 - tooltip: t("placeholder.settings") + - "@default/system-tray" + - "@default/bluetooth" + - "@default/network" + - "@default/media" + - "@default/power" + - "@default/notifications" + - "@default/quick-settings" diff --git a/static/placeholders/default_alter.yml b/static/placeholders/default_alter.yml index 0d690c21..94ac79a6 100644 --- a/static/placeholders/default_alter.yml +++ b/static/placeholders/default_alter.yml @@ -55,20 +55,7 @@ right: ) : icon.TbWorldCancel - - type: media - withMediaControls: true - template: >- - isMuted - ? icon.IoVolumeMuteOutline - : volume >= 0.66 - ? icon.IoVolumeHighOutline - : volume >= 0.33 - ? icon.IoVolumeMediumOutline - : volume != 0 - ? icon.IoVolumeLowOutline - : icon.IoVolumeOffOutline - tooltip: >- - concat(t("placeholder.volume"), ": ", string(round(volume * 100)), "%") + - "@default/media" - type: power tooltip: >- diff --git a/static/plugins/tb_default_bluethoot.yml b/static/plugins/tb_default_bluethoot.yml new file mode 100644 index 00000000..b51782f5 --- /dev/null +++ b/static/plugins/tb_default_bluethoot.yml @@ -0,0 +1,7 @@ +id: "@default/bluetooth" +target: "@seelen/fancy-toolbar" +plugin: + type: device + template: icon.TbBluetoothConnected + onClick: open -> "ms-settings:connecteddevices" + tooltip: t("placeholder.bluetooth_devices") \ No newline at end of file diff --git a/static/plugins/tb_default_date.yml b/static/plugins/tb_default_date.yml new file mode 100644 index 00000000..ff28a4d8 --- /dev/null +++ b/static/plugins/tb_default_date.yml @@ -0,0 +1,6 @@ +id: "@default/date" +target: "@seelen/fancy-toolbar" +plugin: + type: date + template: date + withMiniCalendar: true diff --git a/static/plugins/tb_default_focused_app.yml b/static/plugins/tb_default_focused_app.yml new file mode 100644 index 00000000..8f146d8b --- /dev/null +++ b/static/plugins/tb_default_focused_app.yml @@ -0,0 +1,7 @@ +id: "@default/focused-app" +target: "@seelen/fancy-toolbar" +plugin: + type: generic + template: concat(imgFromExe(window.exe), " ", window.name) + style: + flexShrink: 0 diff --git a/static/plugins/tb_default_focused_app_title.yml b/static/plugins/tb_default_focused_app_title.yml new file mode 100644 index 00000000..729da828 --- /dev/null +++ b/static/plugins/tb_default_focused_app_title.yml @@ -0,0 +1,7 @@ +id: "@default/focused-app-title" +target: "@seelen/fancy-toolbar" +plugin: + type: generic + template: window.title + style: + flexShrink: 2 diff --git a/static/plugins/tb_default_media.yml b/static/plugins/tb_default_media.yml new file mode 100644 index 00000000..4637ace4 --- /dev/null +++ b/static/plugins/tb_default_media.yml @@ -0,0 +1,17 @@ +id: "@default/media" +target: "@seelen/fancy-toolbar" +plugin: + type: media + withMediaControls: true + template: >- + isMuted + ? icon.IoVolumeMuteOutline + : volume >= 0.66 + ? icon.IoVolumeHighOutline + : volume >= 0.33 + ? icon.IoVolumeMediumOutline + : volume != 0 + ? icon.IoVolumeLowOutline + : icon.IoVolumeOffOutline + tooltip: >- + concat(t("placeholder.volume"), ": ", string(round(volume * 100)), "%") \ No newline at end of file diff --git a/static/plugins/tb_default_network.yml b/static/plugins/tb_default_network.yml new file mode 100644 index 00000000..b6b6ffba --- /dev/null +++ b/static/plugins/tb_default_network.yml @@ -0,0 +1,15 @@ +id: "@default/network" +target: "@seelen/fancy-toolbar" +plugin: + type: network + withWlanSelector: true + tooltip: >- + online ? t("placeholder.ethernet_connected") : t("placeholder.ethernet_disconnected") + template: >- + online + ? ( + unequal(usingInterface, null) and equalText(usingInterface.type, "IEEE80211") + ? getIcon("FaWifi", 14) + : icon.FaComputer + ) + : icon.TbWorldCancel \ No newline at end of file diff --git a/static/plugins/tb_default_notifications.yml b/static/plugins/tb_default_notifications.yml new file mode 100644 index 00000000..7c26da39 --- /dev/null +++ b/static/plugins/tb_default_notifications.yml @@ -0,0 +1,10 @@ +id: "@default/notifications" +target: "@seelen/fancy-toolbar" +plugin: + type: notifications + template: >- + count > 0 ? icon.MdNotificationsActive : icon.MdOutlineNotifications + badge: >- + count > 0 ? count : "" + tooltip: >- + concat(t("placeholder.notifications"), ": ", string(count)) diff --git a/static/plugins/tb_default_power.yml b/static/plugins/tb_default_power.yml new file mode 100644 index 00000000..f3459222 --- /dev/null +++ b/static/plugins/tb_default_power.yml @@ -0,0 +1,26 @@ +id: "@default/power" +target: "@seelen/fancy-toolbar" +plugin: + type: power + tooltip: >- + concat(string(battery.percentage), t("placeholder.battery_remaining"), battery.smartCharging ? t("placeholder.smart_charge") : "") + template: >- + concat( + string(equalText(battery.state, "charging") ? concat(getIcon("MdOutlineElectricBolt", 12), " ") : ""), + string(battery.smartCharging ? concat(getIcon("FaHeart", 12), " ") : ""), + string( + battery.percentage > 90 + ? icon.PiBatteryFullFill + : battery.percentage > 66 + ? icon.PiBatteryHighFill + : battery.percentage > 33 + ? icon.PiBatteryMediumFill + : battery.percentage > 5 + ? icon.PiBatteryLowFill + : icon.PiBatteryWarning + ), + " ", + string(battery.percentage), + "%" + ) + onClick: open -> "ms-settings:powersleep" diff --git a/static/plugins/tb_default_quick_settings.yml b/static/plugins/tb_default_quick_settings.yml new file mode 100644 index 00000000..cbb1ba55 --- /dev/null +++ b/static/plugins/tb_default_quick_settings.yml @@ -0,0 +1,6 @@ +id: "@default/quick-settings" +target: "@seelen/fancy-toolbar" +plugin: + type: settings + template: icon.LuSettings2 + tooltip: t("placeholder.settings") diff --git a/static/plugins/tb_default_system_tray.yml b/static/plugins/tb_default_system_tray.yml new file mode 100644 index 00000000..cf26bb69 --- /dev/null +++ b/static/plugins/tb_default_system_tray.yml @@ -0,0 +1,6 @@ +id: "@default/system-tray" +target: "@seelen/fancy-toolbar" +plugin: + type: tray + template: icon.BsThreeDots + tooltip: t("placeholder.open_system_tray") \ No newline at end of file diff --git a/static/plugins/tb_default_user_folder.yml b/static/plugins/tb_default_user_folder.yml new file mode 100644 index 00000000..288bd315 --- /dev/null +++ b/static/plugins/tb_default_user_folder.yml @@ -0,0 +1,9 @@ +id: "@default/user-folder" +target: "@seelen/fancy-toolbar" +plugin: + type: generic + template: concat("@", env.USERNAME) + onClickV2: open(env.USERPROFILE) + tooltip: t("placeholder.open_user_folder") + style: + flexShrink: 0 \ No newline at end of file diff --git a/static/widgets/demo.yml b/static/widgets/demo.yml new file mode 100644 index 00000000..708a2e6a --- /dev/null +++ b/static/widgets/demo.yml @@ -0,0 +1 @@ +id: "@default/demo" \ No newline at end of file