diff --git a/frontend/app/app.tsx b/frontend/app/app.tsx index 0ebddc56..5d821bfc 100644 --- a/frontend/app/app.tsx +++ b/frontend/app/app.tsx @@ -91,7 +91,6 @@ function AppSettingsUpdater() { (windowSettings?.["window:transparent"] || windowSettings?.["window:blur"]) ?? false; const opacity = util.boundNumber(windowSettings?.["window:opacity"] ?? 0.8, 0, 1); let baseBgColor = windowSettings?.["window:bgcolor"]; - console.log("window settings", windowSettings); if (isTransparentOrBlur) { document.body.classList.add("is-transparent"); const rootStyles = getComputedStyle(document.documentElement); diff --git a/frontend/app/block/block.less b/frontend/app/block/block.less index ba55d76b..2e696230 100644 --- a/frontend/app/block/block.less +++ b/frontend/app/block/block.less @@ -62,7 +62,7 @@ &.block-frame-default { position: relative; - padding: 2px; + padding: 1px; .block-frame-default-inner { background-color: var(--block-bg-color); diff --git a/frontend/app/store/global.ts b/frontend/app/store/global.ts index 9e1e5e5c..5f0e5220 100644 --- a/frontend/app/store/global.ts +++ b/frontend/app/store/global.ts @@ -360,7 +360,6 @@ function handleWSEventMessage(msg: WSEventType) { } if (msg.eventtype == "config") { const fullConfig = (msg.data as WatcherUpdate).fullconfig; - console.log("fullConfig", fullConfig); globalStore.set(atoms.fullConfigAtom, fullConfig); return; } diff --git a/frontend/app/tab/tabcontent.tsx b/frontend/app/tab/tabcontent.tsx index c6a3597e..cca7dba9 100644 --- a/frontend/app/tab/tabcontent.tsx +++ b/frontend/app/tab/tabcontent.tsx @@ -4,23 +4,30 @@ import { Block } from "@/app/block/block"; import { CenteredDiv } from "@/element/quickelems"; import { ContentRenderer, NodeModel, PreviewRenderer, TileLayout } from "@/layout/index"; -import { getApi } from "@/store/global"; +import { TileLayoutContents } from "@/layout/lib/types"; +import { atoms, getApi } from "@/store/global"; import * as services from "@/store/services"; import * as WOS from "@/store/wos"; -import { useAtomValue } from "jotai"; +import { atom, useAtomValue } from "jotai"; import * as React from "react"; import { useMemo } from "react"; import "./tabcontent.less"; +const tileGapSizeAtom = atom((get) => { + const settings = get(atoms.settingsAtom); + return settings["window:tilegapsize"]; +}); + const TabContent = React.memo(({ tabId }: { tabId: string }) => { const oref = useMemo(() => WOS.makeORef("tab", tabId), [tabId]); const loadingAtom = useMemo(() => WOS.getWaveObjectLoadingAtom(oref), [oref]); const tabLoading = useAtomValue(loadingAtom); const tabAtom = useMemo(() => WOS.getWaveObjectAtom(oref), [oref]); const tabData = useAtomValue(tabAtom); + const tileGapSize = useAtomValue(tileGapSizeAtom); const tileLayoutContents = useMemo(() => { - const renderBlock: ContentRenderer = (nodeModel: NodeModel) => { + const renderContent: ContentRenderer = (nodeModel: NodeModel) => { return ; }; @@ -33,12 +40,13 @@ const TabContent = React.memo(({ tabId }: { tabId: string }) => { } return { - renderContent: renderBlock, - renderPreview: renderPreview, - tabId: tabId, - onNodeDelete: onNodeDelete, - }; - }, [tabId]); + renderContent, + renderPreview, + tabId, + onNodeDelete, + gapSizePx: tileGapSize, + } as TileLayoutContents; + }, [tabId, tileGapSize]); if (tabLoading) { return ( diff --git a/frontend/app/view/codeeditor/codeeditor.tsx b/frontend/app/view/codeeditor/codeeditor.tsx index 31632e7b..816db811 100644 --- a/frontend/app/view/codeeditor/codeeditor.tsx +++ b/frontend/app/view/codeeditor/codeeditor.tsx @@ -75,7 +75,6 @@ interface CodeEditorProps { const minimapEnabledAtom = atom((get) => { const settings = get(atoms.settingsAtom); - console.log("settings", settings); return settings["editor:minimapenabled"] ?? false; }); @@ -108,7 +107,6 @@ export function CodeEditor({ text, language, filename, onChange, onMount }: Code const editorOpts = useMemo(() => { const opts = defaultEditorOptions(); - console.log("minimapEnabled", minimapEnabled); opts.minimap.enabled = minimapEnabled; return opts; }, [minimapEnabled]); diff --git a/frontend/layout/lib/TileLayout.tsx b/frontend/layout/lib/TileLayout.tsx index c79146ea..612539bd 100644 --- a/frontend/layout/lib/TileLayout.tsx +++ b/frontend/layout/lib/TileLayout.tsx @@ -101,13 +101,15 @@ function TileLayoutComponent({ tabAtom, contents, getCursorPoint }: TileLayoutPr }, 50); }, []); + const gapSizePx = useAtomValue(layoutModel.gapSizePx); + const animationTimeS = useAtomValue(layoutModel.animationTimeS); const tileStyle = useMemo( () => ({ - "--gap-size-px": `${layoutModel.gapSizePx}px`, - "--animation-time-s": `${layoutModel.animationTimeS}s`, + "--gap-size-px": `${gapSizePx}px`, + "--animation-time-s": `${animationTimeS}s`, }) as CSSProperties, - [layoutModel.gapSizePx, layoutModel.animationTimeS] + [gapSizePx, animationTimeS] ); return ( diff --git a/frontend/layout/lib/layoutModel.ts b/frontend/layout/lib/layoutModel.ts index ceaaa80c..08a97395 100644 --- a/frontend/layout/lib/layoutModel.ts +++ b/frontend/layout/lib/layoutModel.ts @@ -56,7 +56,7 @@ interface ResizeContext { afterNodeStartSize: number; } -const DefaultGapSizePx = 5; +const DefaultGapSizePx = 3; const MinNodeSizePx = 40; const DefaultAnimationTimeS = 0.15; @@ -96,12 +96,12 @@ export class LayoutModel { /** * The size of the gap between nodes in CSS pixels. */ - gapSizePx: number; + gapSizePx: PrimitiveAtom; /** * The time a transition animation takes, in seconds. */ - animationTimeS: number; + animationTimeS: PrimitiveAtom; /** * List of nodes that are leafs and should be rendered as a DisplayNode. @@ -183,13 +183,7 @@ export class LayoutModel { * The resize handle size is double the gap size, or double the default gap size, whichever is greater. * @see gapSizePx @see DefaultGapSizePx */ - private resizeHandleSizePx: number; - /** - * Half of the size of the resize handles, in CSS pixels. - * - * @see resizeHandleSizePx This is just a precomputed halving of the resize handle size. - */ - private halfResizeHandleSizePx: number; + private resizeHandleSizePx: Atom; /** * A context used by the resize handles to keep track of precomputed values for the current resize operation. */ @@ -219,10 +213,12 @@ export class LayoutModel { this.renderContent = renderContent; this.renderPreview = renderPreview; this.onNodeDelete = onNodeDelete; - this.gapSizePx = gapSizePx ?? DefaultGapSizePx; - this.halfResizeHandleSizePx = this.gapSizePx > 5 ? this.gapSizePx : DefaultGapSizePx; - this.resizeHandleSizePx = 2 * this.halfResizeHandleSizePx; - this.animationTimeS = animationTimeS ?? DefaultAnimationTimeS; + this.gapSizePx = atom(gapSizePx ?? DefaultGapSizePx); + this.resizeHandleSizePx = atom((get) => { + const gapSizePx = get(this.gapSizePx); + return 2 * (gapSizePx > 5 ? gapSizePx : DefaultGapSizePx); + }); + this.animationTimeS = atom(animationTimeS ?? DefaultAnimationTimeS); this.lastTreeStateGeneration = -1; this.leafs = atom([]); @@ -292,9 +288,14 @@ export class LayoutModel { * @param contents Contains callbacks provided by the TileLayout component. */ registerTileLayout(contents: TileLayoutContents) { + console.log("registerTileLayout", contents); this.renderContent = contents.renderContent; this.renderPreview = contents.renderPreview; this.onNodeDelete = contents.onNodeDelete; + if (contents.gapSizePx !== undefined) { + console.log("setting gapSizePx", contents.gapSizePx); + this.setter(this.gapSizePx, contents.gapSizePx); + } } /** @@ -470,8 +471,9 @@ export class LayoutModel { pendingAction?.type === LayoutTreeActionType.ResizeNode ? (pendingAction as LayoutTreeResizeNodeAction) : null; + const resizeHandleSizePx = this.getter(this.resizeHandleSizePx); const callback = (node: LayoutNode) => - this.updateTreeHelper(node, newAdditionalProps, newLeafs, resizeAction); + this.updateTreeHelper(node, newAdditionalProps, newLeafs, resizeHandleSizePx, resizeAction); if (balanceTree) this.treeState.rootNode = balanceNode(this.treeState.rootNode, callback); else walkNodes(this.treeState.rootNode, callback); @@ -499,6 +501,7 @@ export class LayoutModel { node: LayoutNode, additionalPropsMap: Record, leafs: LayoutNode[], + resizeHandleSizePx: number, resizeAction?: LayoutTreeResizeNodeAction ) { /** @@ -567,15 +570,16 @@ export class LayoutModel { // We only want the resize handles in between nodes, this ensures we have n-1 handles. if (lastChildRect) { const resizeHandleIndex = resizeHandles.length; + const halfResizeHandleSizePx = resizeHandleSizePx / 2; const resizeHandleDimensions: Dimensions = { top: nodeIsRow ? lastChildRect.top - : lastChildRect.top + lastChildRect.height - this.halfResizeHandleSizePx, + : lastChildRect.top + lastChildRect.height - halfResizeHandleSizePx, left: nodeIsRow - ? lastChildRect.left + lastChildRect.width - this.halfResizeHandleSizePx + ? lastChildRect.left + lastChildRect.width - halfResizeHandleSizePx : lastChildRect.left, - width: nodeIsRow ? this.resizeHandleSizePx : lastChildRect.width, - height: nodeIsRow ? lastChildRect.height : this.resizeHandleSizePx, + width: nodeIsRow ? resizeHandleSizePx : lastChildRect.width, + height: nodeIsRow ? lastChildRect.height : resizeHandleSizePx, }; resizeHandles.push({ id: `${node.id}-${resizeHandleIndex}`, @@ -584,8 +588,7 @@ export class LayoutModel { transform: setTransform(resizeHandleDimensions, true, false), flexDirection: node.flexDirection, centerPx: - (nodeIsRow ? resizeHandleDimensions.left : resizeHandleDimensions.top) + - this.halfResizeHandleSizePx, + (nodeIsRow ? resizeHandleDimensions.left : resizeHandleDimensions.top) + halfResizeHandleSizePx, }); } lastChildRect = rect; @@ -750,7 +753,6 @@ export class LayoutModel { if (!this.nodeModels.has(nodeid)) { this.nodeModels.set(nodeid, { additionalProps: addlPropsAtom, - animationTimeS: this.animationTimeS, innerRect: atom((get) => { const addlProps = get(addlPropsAtom); const numLeafs = get(this.numLeafs); diff --git a/frontend/layout/lib/tilelayout.less b/frontend/layout/lib/tilelayout.less index 2daff040..c03ab478 100644 --- a/frontend/layout/lib/tilelayout.less +++ b/frontend/layout/lib/tilelayout.less @@ -49,14 +49,14 @@ cursor: ew-resize; .line { height: 100%; - margin-left: calc(var(--gap-size-px) - 1px); - border-left: 2px solid var(--accent-color); + width: calc(50% + 1px); + border-right: 2px solid var(--accent-color); } } &.flex-column { cursor: ns-resize; .line { - margin-top: calc(var(--gap-size-px) - 1px); + height: calc(50% + 1px); border-bottom: 2px solid var(--accent-color); } } @@ -80,7 +80,6 @@ } &.magnified { - border-radius: calc(var(--block-border-radius) + 4px); background-color: var(--block-bg-solid-color); z-index: var(--zindex-layout-magnified-node); } @@ -110,8 +109,11 @@ overflow: hidden; } - &:not(:only-child) .tile-leaf { - padding: calc(var(--gap-size-px) / 2); + &:not(:only-child), + &:not(.magnified) { + .tile-leaf { + padding: calc(var(--gap-size-px) / 2); + } } } diff --git a/frontend/layout/lib/types.ts b/frontend/layout/lib/types.ts index 7144a8d8..13e74262 100644 --- a/frontend/layout/lib/types.ts +++ b/frontend/layout/lib/types.ts @@ -274,6 +274,21 @@ export const DefaultNodeSize = 10; * nothing in here is specific to the TileLayout itself */ export interface TileLayoutContents { + /** + * The tabId with which this TileLayout is associated. + */ + tabId?: string; + + /** + * The class name to use for the top-level div of the tile layout. + */ + className?: string; + + /** + * The gap between tiles in a layout, in CSS pixels. + */ + gapSizePx?: number; + /** * A callback that accepts the data from the leaf node and displays the leaf contents to the user. */ @@ -287,21 +302,11 @@ export interface TileLayoutContents { * @param data The contents of the node that was deleted. */ onNodeDelete?: (data: TabLayoutData) => Promise; - /** - * The class name to use for the top-level div of the tile layout. - */ - className?: string; - /** * A callback for getting the cursor point in reference to the current window. This removes Electron as a runtime dependency, allowing for better integration with Storybook. * @returns The cursor position relative to the current window. */ getCursorPoint?: () => Point; - - /** - * tabId this TileLayout is associated with - */ - tabId?: string; } export interface ResizeHandleProps { @@ -325,7 +330,6 @@ export interface LayoutNodeAdditionalProps { export interface NodeModel { additionalProps: Atom; - animationTimeS: number; innerRect: Atom; blockNum: Atom; numLeafs: Atom; diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index b1504758..d784d2b6 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -412,6 +412,7 @@ declare global { "window:opacity"?: number; "window:bgcolor"?: string; "window:reducedmotion"?: boolean; + "window:tilegapsize": number; "telemetry:*"?: boolean; "telemetry:enabled"?: boolean; }; diff --git a/pkg/wconfig/defaultconfig/settings.json b/pkg/wconfig/defaultconfig/settings.json index 8c5cb044..78699883 100644 --- a/pkg/wconfig/defaultconfig/settings.json +++ b/pkg/wconfig/defaultconfig/settings.json @@ -5,5 +5,6 @@ "autoupdate:enabled": true, "autoupdate:installonquit": true, "autoupdate:intervalms": 3600000, - "editor:minimapenabled": true + "editor:minimapenabled": true, + "window:tilegapsize": 3 } diff --git a/pkg/wconfig/metaconsts.go b/pkg/wconfig/metaconsts.go index 2d57fae1..6d7dfc80 100644 --- a/pkg/wconfig/metaconsts.go +++ b/pkg/wconfig/metaconsts.go @@ -41,6 +41,7 @@ const ( ConfigKey_WindowOpacity = "window:opacity" ConfigKey_WindowBgColor = "window:bgcolor" ConfigKey_WindowReducedMotion = "window:reducedmotion" + ConfigKey_WindowTileGapSize = "window:tilegapsize" ConfigKey_TelemetryClear = "telemetry:*" ConfigKey_TelemetryEnabled = "telemetry:enabled" diff --git a/pkg/wconfig/settingsconfig.go b/pkg/wconfig/settingsconfig.go index 0c77371f..bc28718d 100644 --- a/pkg/wconfig/settingsconfig.go +++ b/pkg/wconfig/settingsconfig.go @@ -73,6 +73,7 @@ type SettingsType struct { WindowOpacity float64 `json:"window:opacity,omitempty"` WindowBgColor string `json:"window:bgcolor,omitempty"` WindowReducedMotion bool `json:"window:reducedmotion,omitempty"` + WindowTileGapSize int8 `json:"window:tilegapsize"` TelemetryClear bool `json:"telemetry:*,omitempty"` TelemetryEnabled bool `json:"telemetry:enabled,omitempty"`