mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-17 18:25:42 +02:00
[eric] canvas: fullscreen locks canvas panning (drag joined the wheel gate), thirds cut from the tile menus, Applications window gets always-on search + image-only tiles (screenshot > symbol > svg, letters never)
This commit is contained in:
@@ -3,13 +3,12 @@
|
|||||||
export const ZONE_LABELS: Record<string, string> = {
|
export const ZONE_LABELS: Record<string, string> = {
|
||||||
fill: 'Fill', left: 'Left half', right: 'Right half', top: 'Top half', bottom: 'Bottom half',
|
fill: 'Fill', left: 'Left half', right: 'Right half', top: 'Top half', bottom: 'Bottom half',
|
||||||
tl: 'Top left', tr: 'Top right', bl: 'Bottom left', br: 'Bottom right',
|
tl: 'Top left', tr: 'Top right', bl: 'Bottom left', br: 'Bottom right',
|
||||||
t3l: 'Left third', t3c: 'Center third', t3r: 'Right third',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// The one grid every tiling surface renders: the green-dot hover menu and the right-click "Tile to
|
// The one grid every tiling surface renders: the green-dot hover menu and the right-click "Tile to
|
||||||
// zone" submenu both map this, so they can never drift apart on which zones exist.
|
// zone" submenu both map this, so they can never drift apart on which zones exist. Thirds were cut
|
||||||
|
// (Eric 2026-08-09): the geometry still restores an old t3* card fine, the menus just stop offering it.
|
||||||
export const TILE_GROUPS: { label: string; zones: string[] }[] = [
|
export const TILE_GROUPS: { label: string; zones: string[] }[] = [
|
||||||
{ label: 'Fill and halves', zones: ['fill', 'left', 'right', 'top', 'bottom'] },
|
{ label: 'Fill and halves', zones: ['fill', 'left', 'right', 'top', 'bottom'] },
|
||||||
{ label: 'Quarters', zones: ['tl', 'tr', 'bl', 'br'] },
|
{ label: 'Quarters', zones: ['tl', 'tr', 'bl', 'br'] },
|
||||||
{ label: 'Thirds', zones: ['t3l', 't3c', 't3r'] },
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -19,10 +19,11 @@ function hueFor(name: string): number {
|
|||||||
return h % 360;
|
return h % 360;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Every tile is a generated ICON (gradient + monogram): a screenshot crushed to 68px reads as mud,
|
// Never letters or numbers on a tile (Eric 2026-08-09): the app's own screenshot is the icon; an
|
||||||
// so the screenshot lives in the hover preview instead and the row stays dock-uniform.
|
// emoji glyph (a real symbol, not an initial) is the next-best mark; the generic app SVG closes.
|
||||||
function AppTile({ output }: { output: Output }): React.ReactElement {
|
function AppTile({ output }: { output: Output }): React.ReactElement {
|
||||||
const glyph = (output.icon || '').trim();
|
const glyph = (output.icon || '').trim();
|
||||||
|
const glyphIsSymbol = glyph.length > 0 && glyph.length <= 3 && !/[a-z0-9]/i.test(glyph);
|
||||||
const h = hueFor(output.name || '?');
|
const h = hueFor(output.name || '?');
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
@@ -34,14 +35,20 @@ function AppTile({ output }: { output: Output }): React.ReactElement {
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
|
overflow: 'hidden',
|
||||||
boxShadow: 'inset 0 0 0 1px rgba(255,255,255,0.14), 0 6px 18px rgba(0,0,0,0.32)',
|
boxShadow: 'inset 0 0 0 1px rgba(255,255,255,0.14), 0 6px 18px rgba(0,0,0,0.32)',
|
||||||
background: `linear-gradient(160deg, hsl(${h}, 42%, 52%), hsl(${(h + 24) % 360}, 48%, 34%))`,
|
background: `linear-gradient(160deg, hsl(${h}, 42%, 52%), hsl(${(h + 24) % 360}, 48%, 34%))`,
|
||||||
fontSize: glyph && glyph.length <= 3 ? '1.5rem' : '1.375rem',
|
fontSize: '1.5rem',
|
||||||
fontWeight: 590,
|
|
||||||
color: 'rgba(255,255,255,0.94)',
|
color: 'rgba(255,255,255,0.94)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{glyph && glyph.length <= 3 ? glyph : (output.name || '?').trim().charAt(0).toUpperCase()}
|
{output.thumbnail ? (
|
||||||
|
<Box component="img" src={output.thumbnail} alt="" sx={{ width: '100%', height: '100%', objectFit: 'cover' }} />
|
||||||
|
) : glyphIsSymbol ? (
|
||||||
|
glyph
|
||||||
|
) : (
|
||||||
|
<GridViewRoundedIcon sx={{ fontSize: 30, color: 'rgba(255,255,255,0.92)' }} />
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -126,7 +133,7 @@ function ApplicationsWindow({ outputs, onOpenApp, onClose }: ApplicationsWindowP
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{Object.keys(outputs).length > 8 && (
|
{Object.keys(outputs).length > 0 && (
|
||||||
<Box
|
<Box
|
||||||
component="input"
|
component="input"
|
||||||
autoFocus
|
autoFocus
|
||||||
|
|||||||
@@ -514,6 +514,9 @@ export function useCanvasControls(
|
|||||||
// tree, not the DOM: without this guard their clicks started a canvas pan and the preventDefault
|
// tree, not the DOM: without this guard their clicks started a canvas pan and the preventDefault
|
||||||
// killed input focus (the "can't click into the Add-connector fields" bug).
|
// killed input focus (the "can't click into the Add-connector fields" bug).
|
||||||
if (e.currentTarget instanceof Node && e.target instanceof Node && !e.currentTarget.contains(e.target)) return;
|
if (e.currentTarget instanceof Node && e.target instanceof Node && !e.currentTarget.contains(e.target)) return;
|
||||||
|
// Fullscreen has no canvas nav, period (same rule the wheel handler enforces): a drag that
|
||||||
|
// slipped past the fullscreen surface panned the hidden canvas underneath it.
|
||||||
|
if (selectFullscreenCardId(store.getState())) return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
cancelAnimation();
|
cancelAnimation();
|
||||||
cancelInertia();
|
cancelInertia();
|
||||||
|
|||||||
Reference in New Issue
Block a user