mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-17 18:25:42 +02:00
[eric] canvas: app card chrome carries no identity (bare strip); the dock tile is the personalized mark and prefers the app's real thumbnail over any glyph
This commit is contained in:
@@ -645,16 +645,6 @@ const DashboardViewCard: React.FC<Props> = ({
|
||||
const dockActive = !!dockRect && !dragging && !localResize && !isTiled && !isMinimized;
|
||||
const tiledSize = useTiledCard({ cardId: cardKey, zone: tileZone, active: !isMinimized, originX: displayX, originY: displayY, getCamera: getCanvasState });
|
||||
|
||||
// Same identity math as the dock and Applications window, shrunk to chrome size.
|
||||
const appHue = ((): number => {
|
||||
let h = 0;
|
||||
const name = output.name || '?';
|
||||
for (let i = 0; i < name.length; i++) h = (h * 31 + name.charCodeAt(i)) >>> 0;
|
||||
return h % 360;
|
||||
})();
|
||||
const p_glyph = (output.icon || '').trim();
|
||||
const appGlyph = p_glyph && p_glyph.length <= 3 ? p_glyph : (output.name || '?').trim().charAt(0).toUpperCase();
|
||||
|
||||
// The old 8-icon header cluster, demoted behind one kebab: view switcher, new window, toolbar
|
||||
// collapse, then the same rows the card's right-click menu carries.
|
||||
const headerKebabRows = (): CardMenuRow[] => ([
|
||||
@@ -817,29 +807,6 @@ const DashboardViewCard: React.FC<Props> = ({
|
||||
<Box onPointerDown={(e) => e.stopPropagation()} sx={{ display: 'flex', alignItems: 'center', flexShrink: 0, mr: 0.25 }}>
|
||||
<WindowControls onClose={() => handleRemove()} onMinimize={onMinimize} onTile={onTile} tiled={!!tileZone} />
|
||||
</Box>
|
||||
{/* Centered identity: the app's own monogram tile, no name (bare-chrome grammar shared with Settings/Marketplace; the tile matches the dock and Applications window). */}
|
||||
<Box sx={{ position: 'absolute', left: '50%', transform: 'translateX(-50%)', display: 'flex', alignItems: 'center', gap: 0.5, pointerEvents: 'none' }} title={output.name}>
|
||||
<Box
|
||||
sx={{
|
||||
width: 17,
|
||||
height: 17,
|
||||
borderRadius: '5px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
fontSize: '0.5625rem',
|
||||
fontWeight: 700,
|
||||
color: 'rgba(255,255,255,0.94)',
|
||||
background: `linear-gradient(160deg, hsl(${appHue}, 42%, 52%), hsl(${(appHue + 24) % 360}, 48%, 34%))`,
|
||||
boxShadow: 'inset 0 0 0 1px rgba(255,255,255,0.14)',
|
||||
}}
|
||||
>
|
||||
{appGlyph}
|
||||
</Box>
|
||||
{instance > 1 && (
|
||||
<Typography sx={{ fontSize: '0.6875rem', fontWeight: 600, color: c.text.ghost }}>#{instance}</Typography>
|
||||
)}
|
||||
</Box>
|
||||
<Box sx={{ flex: 1 }} />
|
||||
|
||||
{showControls && (
|
||||
|
||||
@@ -2,11 +2,21 @@ import React, { useState } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import type { DockEntry } from './dockEntries';
|
||||
|
||||
/** A tile shows its site favicon OR the generic glyph, never the glyph peeking out from behind the favicon. */
|
||||
/** A tile shows its real image (site favicon, app thumbnail) OR the generic SVG glyph, never
|
||||
* letters and never the glyph peeking out from behind an image. */
|
||||
export function DockTileIcon({ entry }: { entry: DockEntry }): React.ReactElement {
|
||||
const [faviconFailed, setFaviconFailed] = useState(false);
|
||||
if (!entry.faviconUrl || faviconFailed) return <>{entry.icon}</>;
|
||||
return (
|
||||
<Box component="img" src={entry.faviconUrl} alt="" onError={() => setFaviconFailed(true)} sx={{ borderRadius: '6px' }} />
|
||||
);
|
||||
const [imageFailed, setImageFailed] = useState(false);
|
||||
if (entry.faviconUrl && !imageFailed) {
|
||||
return (
|
||||
<Box component="img" src={entry.faviconUrl} alt="" onError={() => setImageFailed(true)} sx={{ borderRadius: '6px' }} />
|
||||
);
|
||||
}
|
||||
// An app's own screenshot fills the whole tile: the most personalized mark it can carry.
|
||||
if (entry.kind === 'view' && entry.thumbnail && !imageFailed) {
|
||||
return (
|
||||
<Box component="img" src={entry.thumbnail} alt="" onError={() => setImageFailed(true)}
|
||||
sx={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover' }} />
|
||||
);
|
||||
}
|
||||
return <>{entry.icon}</>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user