diff --git a/manifest.json b/manifest.json index 7ec1482..8760cf0 100644 --- a/manifest.json +++ b/manifest.json @@ -11,5 +11,6 @@ ], "icons": { "128": "icon.png" - } + }, + "incognito": "spanning" } \ No newline at end of file diff --git a/public/styles.css b/public/styles.css index 8edcbe6..8c82000 100644 --- a/public/styles.css +++ b/public/styles.css @@ -16,17 +16,23 @@ body { /* Base styles for widget containers */ .container { position: absolute; - background: rgba(255, 255, 255, 0.2); - backdrop-filter: blur(10px); - -webkit-backdrop-filter: blur(10px); - border: 1px solid rgba(255, 255, 255, 0.3); - border-radius: 5px; - padding: 10px; - box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; z-index: 0; + container-type: size; + overflow: hidden; + border: 1px solid rgba(255, 255, 255, 0); + padding: 10px; + border-radius: 5px; +} + +.aero { + background: rgba(255, 255, 255, 0.2); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + border-color: rgba(255, 255, 255, 0.3); + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); } /* Styles for the close button */ @@ -45,15 +51,6 @@ body { line-height: 16px; text-align: center; cursor: pointer; - transition: background 0.2s; -} - -.close-button:hover { - background: #ff4444; -} - -.close-button:active { - background: #cc0000; } /* Styles for the settings button */ @@ -72,7 +69,6 @@ body { align-items: center; justify-content: center; cursor: pointer; - transition: background 0.2s; } .settings-button:hover { @@ -89,6 +85,14 @@ body { font-size: 48px; font-family: 'IBM Plex Mono', monospace; text-align: center; + font-size: 50cqmin; +} + +.timezone-display{ + font-size: small; + text-align: center; + color: #ffffff; + font-size: 15cqmin; } /* SearchWidget form */ @@ -145,7 +149,6 @@ body { display: flex; align-items: center; justify-content: center; - transition: background 0.2s; } .settings-toggle:hover { @@ -154,9 +157,7 @@ body { /* Main settings modal */ .settings-modal { - position: fixed; - top: 0; - left: 0; + position: absolute; width: 100%; height: 100%; display: flex; @@ -259,9 +260,3 @@ body { width: 100%; height: 1px; } - -.timezone-display{ - font-size: small; - text-align: center; - color: #ffffff; -} \ No newline at end of file diff --git a/src/renderer/components/SettingsPanel.tsx b/src/renderer/components/GlobalSettingsPanel.tsx similarity index 73% rename from src/renderer/components/SettingsPanel.tsx rename to src/renderer/components/GlobalSettingsPanel.tsx index 6461f36..978aa89 100644 --- a/src/renderer/components/SettingsPanel.tsx +++ b/src/renderer/components/GlobalSettingsPanel.tsx @@ -1,29 +1,27 @@ -import React, { useState } from 'react'; +import React, { useCallback, useState } from 'react'; import { CogwheelIcon } from './CogwheelIcon'; -import { useAtom, useSetAtom } from 'jotai'; +import { useAtom } from 'jotai'; import { editState } from '../state/edit.state'; import { showGridState } from '../state/showGrid.state'; import { intitialWidgetData } from '../defaults'; import { WidgetData, WidgetTypes } from '../types'; -import { modalContent, modalVisible } from '../state/modalOverlay.state'; import { ModalOverlay } from './ModalOverlay'; +import { backgroundImageState } from '../state/backgroundImage.state'; interface SettingsPanelProps { - backgroundImage: string, - setBackgroundImage: (url: string) => void, addWidget: (widget: WidgetData) => void, } -export const SettingsPanel: React.FC = ({ backgroundImage, setBackgroundImage, addWidget }) => { - const [editEnabled, setEditEnabled] = useAtom(editState); - const [showGrid, setShowGrid] = useAtom(showGridState); +export const GlobalSettingsPanel: React.FC = ({ + addWidget +}) => { const [isModalShowing, setModalShowing] = useState(false); - const createWidget = (type: WidgetTypes) => { - const newWidgetData = intitialWidgetData(type); - addWidget(newWidgetData) - }; + const [editEnabled, setEditEnabled] = useAtom(editState); + const [showGrid, setShowGrid] = useAtom(showGridState); + const [backgroundImage, setBackgroundImage] = useAtom(backgroundImageState) + const createWidget = (type: WidgetTypes) => addWidget(intitialWidgetData(type)); return ( <> @@ -49,7 +47,7 @@ export const SettingsPanel: React.FC = ({ backgroundImage, s setEditEnabled(b => !b)} + onChange={() => setEditEnabled(!editEnabled)} />
diff --git a/src/renderer/components/NewTab.tsx b/src/renderer/components/NewTab.tsx index bda2cfb..dc393a9 100644 --- a/src/renderer/components/NewTab.tsx +++ b/src/renderer/components/NewTab.tsx @@ -1,25 +1,30 @@ -import React, { useState, useEffect } from 'react'; -import { useAtomValue } from 'jotai' +import React, { useState, useEffect, useCallback, Suspense, startTransition } from 'react'; +import { useAtom, useAtomValue } from 'jotai' import { WidgetFactory } from './WidgetFactory'; -import { SettingsPanel } from './SettingsPanel'; -import { loadableWidgetsState } from '../state/widget.state'; +import { GlobalSettingsPanel } from './GlobalSettingsPanel'; import { showGridState } from '../state/showGrid.state'; import { WidgetData } from '../types'; -import { loadableBackgroundImageState } from '../state/backgroundImage.state'; import { settingsService } from '../services/settingsService'; -import { ModalOverlay } from './ModalOverlay'; +import { backgroundImageState } from '../state/backgroundImage.state'; +import { widgetState } from '../state/widget.state'; const GRID_COLS = 36; const GRID_ROWS = 18; +const coloredGrindlines = (i:number, max: number) => { + let color; + if(i === max/2){ + color = '#FF3333' + } + return { background: color } +} + + export const NewTab: React.FC = () => { const [gridSize, setGridSize] = useState({ width: window.innerWidth / GRID_COLS, height: window.innerHeight / GRID_ROWS }); - const [widgets, setWidgets] = useState([]) - const [backgroundImage, setBackgroundImage] = useState('') - - const showGrid = useAtomValue(showGridState) - const loadingWidgets = useAtomValue(loadableWidgetsState) - const loadingBackgroundImage = useAtomValue(loadableBackgroundImageState) + const [showGrid] = useAtom(showGridState) + const [widgets, setWidgets] = useAtom(widgetState) + const [backgroundImage] = useAtom(backgroundImageState) useEffect(() => { const handleResize = () => { @@ -30,41 +35,60 @@ export const NewTab: React.FC = () => { }; window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); - }) + }, [window.innerWidth, window.innerHeight]) - useEffect(() => loadingBackgroundImage.state === 'hasData' ? setBackgroundImage(loadingBackgroundImage.data) : undefined, [loadingBackgroundImage]); - useEffect(() => loadingWidgets.state === 'hasData' ? setWidgets(loadingWidgets.data) : undefined, [loadingWidgets]); useEffect(() => { document.body.style.backgroundImage = `url(${backgroundImage})` }, [backgroundImage]); - const updateWidget = (id: string, updates: Partial) => { - const updatedWidgets = widgets.map(w => - w.id === id ? { ...w, ...updates } : w - ); - setWidgets(updatedWidgets); - settingsService.saveSetting('widgets', updatedWidgets) - }; + const updateWidget = useCallback( + (id: string, updates: Partial) => { + console.log(id, updates) - const addWidget = (data: WidgetData) => { - const updatedWidgets = [...widgets, data] - setWidgets([...widgets, data]) - settingsService.saveSetting('widgets', updatedWidgets) - } + const updatedWidgets = widgets.map(w => + w.id === id ? { ...w, ...updates } : w + ); + setWidgets(updatedWidgets) + }, + [widgets, setWidgets, settingsService] + ); + + const addWidget = useCallback( + (data: WidgetData) => { + const updatedWidgets = [...widgets, data] + setWidgets(updatedWidgets) + }, + [widgets, setWidgets, settingsService] + ); + + const removeWidget = useCallback( + (widgetId: string) => { + const updatedWidgets = widgets.filter(widget => widget.id !== widgetId) + setWidgets(updatedWidgets) + }, + [widgets, setWidgets, settingsService] + ); return ( - <> - - }> + {showGrid && (
{Array.from({ length: GRID_COLS + 1 }).map((_, i) => ( -
+
))} {Array.from({ length: GRID_ROWS + 1 }).map((_, i) => ( -
+
))}
)} @@ -74,8 +98,9 @@ export const NewTab: React.FC = () => { widget={widget} gridSize={gridSize} updateWidget={updateWidget} + removeWidget={removeWidget} /> ))} - + ); }; \ No newline at end of file diff --git a/src/renderer/components/SearchWidget.tsx b/src/renderer/components/SearchWidget.tsx index b857701..1758129 100644 --- a/src/renderer/components/SearchWidget.tsx +++ b/src/renderer/components/SearchWidget.tsx @@ -1,54 +1,78 @@ -import React from 'react'; -import { SearchWidgetData, WidgetExport } from '../types'; +import React, { useCallback, useEffect, useState } from 'react'; +import { GlobalSettings, SearchWidgetData, WidgetExport } from '../types'; +import { searchEngineState } from '../state/searchEngines.state'; +import { useAtom, useAtomValue } from 'jotai'; interface SearchWidgetProps { widget: SearchWidgetData; updateWidget: (id: string, update: Partial) => void } -const searchEngines: { [key in SearchWidgetData['engine']]: string } = { - Google: 'https://www.google.com/search?q=', - Bing: 'https://www.bing.com/search?q=', - DuckDuckGo: 'https://duckduckgo.com/?q=', - Yandex: 'https://yandex.com/search/?text=' -}; +const makeSearchString = (searchStringTemplate: string, query: string) => searchStringTemplate.replace('{s}', encodeURIComponent(query)) -const SearchWidgetComponent: React.FC = ({ widget }) => { - const handleSearch = (e: React.FormEvent) => { - e.preventDefault(); - const query = (e.currentTarget.elements.namedItem('query') as HTMLInputElement).value; - if (query) { - setTimeout(() => { - window.open(`${searchEngines[widget.engine]}${encodeURIComponent(query)}`, '_blank') - }, 200) - } - }; +const SearchWidgetComponent: React.FC = ({ widget, updateWidget }) => { + + const [availableEngines] = useAtom(searchEngineState) + + const handleSearch = useCallback( + (e: React.FormEvent) => { + e.preventDefault(); + const query = (e.currentTarget.elements.namedItem('query') as HTMLInputElement).value; + + if (query) { + widget.engines.forEach(engine => { + if (!(engine in availableEngines)) { + return + } + setTimeout(() => { + window.open(makeSearchString(availableEngines[engine], query), '_blank') + }, 200) + }) + } + }, + [availableEngines, widget] + ); return (
- +
); }; const SearchWidgetSettings = ({ widget, updateWidget }: SearchWidgetProps) => { - const handleEngineChange = (e: React.ChangeEvent) => { - updateWidget(widget.id, { engine: e.target.value as SearchWidgetData['engine'] }); - }; + const [availableEngines] = useAtom(searchEngineState) - return ( - + const handleEngineChange = useCallback( + (e: any) => { + let engines = [...widget.engines] + if (e.target.checked) { + engines.push(e.target.value) + } else { + engines = engines.filter(engine => engine !== e.target.value) + } + updateWidget(widget.id, { engines }) + }, + [updateWidget, widget] ); + + return (<> + {'Search Engine(s):'} + {Object.keys(availableEngines).map((availableEngine: string) => + + )} + ); }; -export const SearchWidget:WidgetExport = { +export const SearchWidget: WidgetExport = { widget: SearchWidgetComponent, settings: SearchWidgetSettings } \ No newline at end of file diff --git a/src/renderer/components/SettingsComponent.tsx b/src/renderer/components/SettingsComponent.tsx new file mode 100644 index 0000000..d7c5976 --- /dev/null +++ b/src/renderer/components/SettingsComponent.tsx @@ -0,0 +1,44 @@ +import { ReactElement } from "react" +import { WidgetData } from "../types" + +type GenericSettingsProps = { + widgetData: WidgetData + updateWidget: (id: string, data: Partial) => void + children: ReactElement | ReactElement[] +} + +export function SettingsComponent({ + widgetData, + updateWidget, + children +}: GenericSettingsProps) { + return <> + {children} + + + + +} \ No newline at end of file diff --git a/src/renderer/components/Widget.tsx b/src/renderer/components/Widget.tsx index 5ab3557..9d6a24c 100644 --- a/src/renderer/components/Widget.tsx +++ b/src/renderer/components/Widget.tsx @@ -1,33 +1,35 @@ -import React, { useRef, useState, useEffect, ReactElement } from 'react'; +import React, { useRef, useState, useEffect, ReactElement, useCallback, startTransition } from 'react'; import { WidgetData } from '../types'; import { CogwheelIcon } from './CogwheelIcon'; import { useAtomValue } from 'jotai'; import { editState } from '../state/edit.state'; import { CloseButton } from './Closebutton'; import { ModalOverlay } from './ModalOverlay'; +import { SettingsComponent } from './SettingsComponent'; +import { debounce, debounceTime } from 'rxjs'; interface WidgetProps { - widget: WidgetData; + widgetData: WidgetData; gridSize: { width: number; height: number }; children: React.ReactNode; settingsContent: ReactElement; - updateWidget: (id: string, data: Partial) => void + updateWidget: (id: string, data: Partial) => void; + removeWidget: (id: string) => void; } -export const Widget: React.FC = ({ widget, gridSize, children, settingsContent, updateWidget }) => { +export const Widget: React.FC = ({ widgetData, gridSize, children, settingsContent, updateWidget, removeWidget }) => { const widgetRef = useRef(null); const modalRef = useRef(null); + const [isDragging, setIsDragging] = useState(false); const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 }); const [isSettingsOpen, setSettingsOpen] = useState(false); - const [widthInput, setWidthInput] = useState(widget.gridWidth); - const [heightInput, setHeightInput] = useState(widget.gridHeight); - const isDraggable = useAtomValue(editState) + const isEditable = useAtomValue(editState) const snapToGrid = (pos: number, grid: number) => Math.round(pos / grid); const handleMouseDown = (e: React.MouseEvent) => { - if (!isDraggable || isSettingsOpen) { + if (!isEditable || isSettingsOpen) { return } @@ -48,7 +50,6 @@ export const Widget: React.FC = ({ widget, gridSize, children, sett e.preventDefault(); const newGridX = snapToGrid(e.clientX - dragOffset.x, gridSize.width); const newGridY = snapToGrid(e.clientY - dragOffset.y, gridSize.height); - widgetRef.current.style.left = `${newGridX * gridSize.width}px`; widgetRef.current.style.top = `${newGridY * gridSize.height}px`; } @@ -58,9 +59,14 @@ export const Widget: React.FC = ({ widget, gridSize, children, sett if (isDragging && widgetRef.current) { setIsDragging(false); const rect = widgetRef.current.getBoundingClientRect(); - const newGridX = snapToGrid(rect.left, gridSize.width); - const newGridY = snapToGrid(rect.top, gridSize.height); - updateWidget(widget.id, { gridX: newGridX, gridY: newGridY }); + const gridX = snapToGrid(rect.left, gridSize.width); + const gridY = snapToGrid(rect.top, gridSize.height); + if(gridX !== widgetData.gridX || gridY !== widgetData.gridY){ + // overwrite the values so prevent a visual "bounce" + widgetData.gridX = gridX; + widgetData.gridY = gridY; + updateWidget(widgetData.id, { gridX, gridY }); + } } }; @@ -70,13 +76,6 @@ export const Widget: React.FC = ({ widget, gridSize, children, sett } }; - - useEffect(() => { - const newWidth = Math.max(1, widthInput); - const newHeight = Math.max(1, heightInput); - updateWidget(widget.id, { gridWidth: newWidth, gridHeight: newHeight }); - }, [heightInput, widthInput]) - useEffect(() => { if (isDragging) { window.addEventListener('mousemove', handleMouseMove); @@ -101,36 +100,33 @@ export const Widget: React.FC = ({ widget, gridSize, children, sett useEffect(() => { if (widgetRef.current && !isDragging) { - widgetRef.current.style.left = `${widget.gridX * gridSize.width}px`; - widgetRef.current.style.top = `${widget.gridY * gridSize.height}px`; - widgetRef.current.style.width = `${(widget.gridWidth) * gridSize.width}px`; - widgetRef.current.style.height = `${(widget.gridHeight) * gridSize.height}px`; + widgetRef.current.style.left = `${widgetData.gridX * gridSize.width}px`; + widgetRef.current.style.top = `${widgetData.gridY * gridSize.height}px`; + widgetRef.current.style.width = `${(widgetData.gridWidth) * gridSize.width}px`; + widgetRef.current.style.height = `${(widgetData.gridHeight) * gridSize.height}px`; } - }, [widget.gridX, widget.gridY, widget.gridWidth, widget.gridHeight, gridSize, isDragging]); - - return ( + }, [widgetData, gridSize, isDragging]); + return (<> + + + {settingsContent} + +
- - - {settingsContent} - - - {isDraggable && <> - undefined /*removeWidget(widget.id)*/} /> + {isEditable && <> + removeWidget(widgetData.id)} />
- ); -}; - - -type GenericSettingsProps = { - widthInput: number; - setWidthInput: (n: number) => void; - heightInput: number; - setHeightInput: (n: number) => void; - children: ReactElement | ReactElement[] -} - -function SettingsComponent({ widthInput, setWidthInput, heightInput, setHeightInput, children }: GenericSettingsProps) { - return <> - {children} - - - -} \ No newline at end of file + ); +}; \ No newline at end of file diff --git a/src/renderer/components/WidgetFactory.tsx b/src/renderer/components/WidgetFactory.tsx index 9c69a19..7e6748e 100644 --- a/src/renderer/components/WidgetFactory.tsx +++ b/src/renderer/components/WidgetFactory.tsx @@ -7,7 +7,8 @@ import { ClockWidget } from './ClockWidget'; interface WidgetFactoryProps { widget: WidgetData; gridSize: { width: number; height: number }; - updateWidget: (id: string, data: Partial) => void + updateWidget: (id: string, data: Partial) => void; + removeWidget: (id:string) => void; } const WidgetMap: { [key in WidgetTypes]: WidgetExport } = { @@ -15,17 +16,18 @@ const WidgetMap: { [key in WidgetTypes]: WidgetExport } = { 'search': SearchWidget } -export const WidgetFactory: React.FC = ({ widget, gridSize, updateWidget }) => { +export const WidgetFactory: React.FC = ({ widget, gridSize, updateWidget, removeWidget }) => { const Wdgt = WidgetMap[widget.type] const component = const settings = Wdgt.settings({ widget: widget, updateWidget }) return ( {component} diff --git a/src/renderer/defaults.ts b/src/renderer/defaults.ts index 0f511ce..8a2aa81 100644 --- a/src/renderer/defaults.ts +++ b/src/renderer/defaults.ts @@ -1,35 +1,48 @@ import { GlobalSettings, SearchWidgetData, ClockWidgetData, WidgetTypes, WidgetData } from './types'; -export const DEFAULT_SETTINGS: GlobalSettings = { - backgroundUrl: '', - widgets: [], - editEnabled: true, - showGrid: true -}; + export const intitialWidgetData = (type: WidgetTypes): WidgetData => { switch (type) { case 'clock': return { - gridHeight: 2, + gridHeight: 3, gridWidth: 6, gridX: 15, gridY: 6, - timezone: 'UTC', + timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, showSeconds: false, use24Hour: true, type: 'clock', + background: true, id: `${type}-${Date.now()}` } as ClockWidgetData case 'search': return { - gridHeight: 2, + gridHeight: 1, gridWidth: 10, gridX: 13, gridY: 6, id: `${type}-${Date.now()}`, type: 'search', - engine: 'Google' + engines: ['Google'], + background: true, } as SearchWidgetData } -} \ No newline at end of file +} + +export const DEFAULT_SETTINGS: GlobalSettings = { + backgroundUrl: 'https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Cat_August_2010-4.jpg/2880px-Cat_August_2010-4.jpg', + widgets: [ + intitialWidgetData('search'), + intitialWidgetData('clock') + ], + editEnabled: true, + showGrid: true, + searchEngines: { + Google: 'https://www.google.com/search?q={s}', + Bing: 'https://www.bing.com/search?q={s}', + DuckDuckGo: 'https://duckduckgo.com/?q={s}', + Yandex: 'https://yandex.com/search/?text={s}' + } +}; \ No newline at end of file diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx index eda0818..03337a9 100644 --- a/src/renderer/index.tsx +++ b/src/renderer/index.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { createRoot } from 'react-dom/client'; import { App } from './App'; diff --git a/src/renderer/services/settingsService.ts b/src/renderer/services/settingsService.ts index 5b6f6ee..fc1d93e 100644 --- a/src/renderer/services/settingsService.ts +++ b/src/renderer/services/settingsService.ts @@ -10,7 +10,7 @@ export const settingsService = { getSetting: async (key: K): Promise => { const loaded = await chrome.storage.sync.get([key]) - return loaded[key] as GlobalSettings[K] + return loaded[key] !== undefined ? loaded[key] as GlobalSettings[K] : DEFAULT_SETTINGS[key] }, }; \ No newline at end of file diff --git a/src/renderer/state/backgroundImage.state.ts b/src/renderer/state/backgroundImage.state.ts index 9d0f10a..ebe36ae 100644 --- a/src/renderer/state/backgroundImage.state.ts +++ b/src/renderer/state/backgroundImage.state.ts @@ -1,9 +1,3 @@ -import { atomWithObservable, loadable } from "jotai/utils"; -import { settingsService } from "../services/settingsService"; -import { from } from 'rxjs'; +import { globalSettingsAtom } from "./globalSettings.atom"; -const backgroundImageState = atomWithObservable(() => - from(settingsService.getSetting('backgroundUrl')) -); - -export const loadableBackgroundImageState = loadable(backgroundImageState) \ No newline at end of file +export const backgroundImageState = globalSettingsAtom('backgroundUrl') \ No newline at end of file diff --git a/src/renderer/state/edit.state.ts b/src/renderer/state/edit.state.ts index fb523db..165c961 100644 --- a/src/renderer/state/edit.state.ts +++ b/src/renderer/state/edit.state.ts @@ -1,4 +1,3 @@ -import { atom } from "jotai"; -import { DEFAULT_SETTINGS } from "../defaults"; +import { globalSettingsAtom } from "./globalSettings.atom"; -export const editState = atom(DEFAULT_SETTINGS.editEnabled) \ No newline at end of file +export const editState = globalSettingsAtom("editEnabled") \ No newline at end of file diff --git a/src/renderer/state/globalSettings.atom.ts b/src/renderer/state/globalSettings.atom.ts new file mode 100644 index 0000000..b4541ce --- /dev/null +++ b/src/renderer/state/globalSettings.atom.ts @@ -0,0 +1,28 @@ +import { settingsService } from "../services/settingsService"; +import { atom } from "jotai"; +import { GlobalSettings } from "../types"; +import { DEFAULT_SETTINGS } from "../defaults"; + +export const globalSettingsAtom = (key: T) => { + const storage = atom(undefined) + + return atom( + async (get) => { + const existing = get(storage) + + if (existing === undefined) { + const remoteValue = await settingsService.getSetting(key) + console.log("load", key, remoteValue) + return remoteValue + } + return existing + }, + async (get, set, update: GlobalSettings[T]) => { + console.log("save", key, update) + await settingsService.saveSetting(key, update) + set(storage, update) + } + ); +} + + diff --git a/src/renderer/state/modalOverlay.state.ts b/src/renderer/state/modalOverlay.state.ts deleted file mode 100644 index f8a5152..0000000 --- a/src/renderer/state/modalOverlay.state.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { atom } from "jotai"; -import { ReactNode } from "react"; - -export const modalVisible = atom(false) -export const modalContent = atom(undefined) \ No newline at end of file diff --git a/src/renderer/state/searchEngines.state.ts b/src/renderer/state/searchEngines.state.ts new file mode 100644 index 0000000..6df1be3 --- /dev/null +++ b/src/renderer/state/searchEngines.state.ts @@ -0,0 +1,3 @@ +import { globalSettingsAtom } from "./globalSettings.atom"; + +export const searchEngineState = globalSettingsAtom('searchEngines') \ No newline at end of file diff --git a/src/renderer/state/showGrid.state.ts b/src/renderer/state/showGrid.state.ts index 6bf10ac..c91c696 100644 --- a/src/renderer/state/showGrid.state.ts +++ b/src/renderer/state/showGrid.state.ts @@ -1,4 +1,3 @@ -import { atom } from "jotai"; -import { DEFAULT_SETTINGS } from "../defaults"; +import { globalSettingsAtom } from "./globalSettings.atom"; -export const showGridState = atom(DEFAULT_SETTINGS.showGrid) \ No newline at end of file +export const showGridState = globalSettingsAtom('showGrid') \ No newline at end of file diff --git a/src/renderer/state/widget.state.ts b/src/renderer/state/widget.state.ts index 3891a4a..b0ee4d6 100644 --- a/src/renderer/state/widget.state.ts +++ b/src/renderer/state/widget.state.ts @@ -1,9 +1,3 @@ -import { atomWithObservable, loadable } from "jotai/utils"; -import { settingsService } from "../services/settingsService"; -import { from } from 'rxjs'; +import { globalSettingsAtom } from "./globalSettings.atom"; -const widgetsState = atomWithObservable(() => - from(settingsService.getSetting('widgets')) -); - -export const loadableWidgetsState = loadable(widgetsState) \ No newline at end of file +export const widgetState = globalSettingsAtom('widgets') \ No newline at end of file diff --git a/src/renderer/types.ts b/src/renderer/types.ts index 96e0f1b..5abfac9 100644 --- a/src/renderer/types.ts +++ b/src/renderer/types.ts @@ -5,12 +5,13 @@ export interface WidgetData { gridY: number; gridWidth: number; gridHeight: number; + background: boolean; [key: string]: any; } export interface SearchWidgetData extends WidgetData { type: 'search'; - engine: 'Google' | 'Bing' | 'DuckDuckGo' | 'Yandex'; + engines: Array; } export interface ClockWidgetData extends WidgetData { @@ -27,6 +28,7 @@ export interface GlobalSettings { widgets: WidgetData[]; editEnabled: boolean; showGrid: boolean; + searchEngines: { [key in string]: string} } export type WidgetExport, S = (...a:any[]) =>JSX.Element > = {