feat: refactor favicon and logo assets
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 32 KiB |
@@ -1,9 +1,60 @@
|
||||
<svg width="24" height="24" viewBox="0 0 70 70" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(35, 35) scale(0.95) translate(-35, -35)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M0 13H35V58H0V13ZM26.25 22.1957H8.75V48.701H26.25V22.1957Z"
|
||||
fill="#808080"/>
|
||||
<path d="M43.75 13H70V22.1957H52.5V48.701H70V57.8967H43.75V13Z"
|
||||
fill="#808080"/>
|
||||
<svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="bgGradient" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#303030"/>
|
||||
<stop offset="100%" stop-color="#141414"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- Background -->
|
||||
<rect x="0" y="0" width="128" height="128" rx="26" ry="26" fill="url(#bgGradient)"/>
|
||||
|
||||
<!-- OpenChamber logo centered -->
|
||||
<g transform="translate(64, 64) scale(1)">
|
||||
<!-- Left face -->
|
||||
<path d="M0 0 L-41.568 -24 L-41.568 24 L0 48 Z" fill="white" fill-opacity="0.15" stroke="white" stroke-width="1.5" stroke-linejoin="round"/>
|
||||
<!-- Left face grid cells -->
|
||||
<path d="M0 0 L-10.392 -6 L-10.392 6 L0 12 Z" fill="white" fill-opacity="0.07"/>
|
||||
<path d="M-10.392 -6 L-20.784 -12 L-20.784 0 L-10.392 6 Z" fill="white" fill-opacity="0.16"/>
|
||||
<path d="M-20.784 -12 L-31.176 -18 L-31.176 -6 L-20.784 0 Z" fill="white" fill-opacity="0.05"/>
|
||||
<path d="M-31.176 -18 L-41.568 -24 L-41.568 -12 L-31.176 -6 Z" fill="white" fill-opacity="0.19"/>
|
||||
<path d="M0 12 L-10.392 6 L-10.392 18 L0 24 Z" fill="white" fill-opacity="0.12"/>
|
||||
<path d="M-10.392 6 L-20.784 0 L-20.784 12 L-10.392 18 Z" fill="white" fill-opacity="0.04"/>
|
||||
<path d="M-20.784 0 L-31.176 -6 L-31.176 6 L-20.784 12 Z" fill="white" fill-opacity="0.18"/>
|
||||
<path d="M-31.176 -6 L-41.568 -12 L-41.568 0 L-31.176 6 Z" fill="white" fill-opacity="0.09"/>
|
||||
<path d="M0 24 L-10.392 18 L-10.392 30 L0 36 Z" fill="white" fill-opacity="0.14"/>
|
||||
<path d="M-10.392 18 L-20.784 12 L-20.784 24 L-10.392 30 Z" fill="white" fill-opacity="0.11"/>
|
||||
<path d="M-20.784 12 L-31.176 6 L-31.176 18 L-20.784 24 Z" fill="white" fill-opacity="0.16"/>
|
||||
<path d="M-31.176 6 L-41.568 0 L-41.568 12 L-31.176 18 Z" fill="white" fill-opacity="0.05"/>
|
||||
<path d="M0 36 L-10.392 30 L-10.392 42 L0 48 Z" fill="white" fill-opacity="0.19"/>
|
||||
<path d="M-10.392 30 L-20.784 24 L-20.784 36 L-10.392 42 Z" fill="white" fill-opacity="0.07"/>
|
||||
<path d="M-20.784 24 L-31.176 18 L-31.176 30 L-20.784 36 Z" fill="white" fill-opacity="0.12"/>
|
||||
<path d="M-31.176 18 L-41.568 12 L-41.568 24 L-31.176 30 Z" fill="white" fill-opacity="0.04"/>
|
||||
<!-- Right face -->
|
||||
<path d="M0 0 L41.568 -24 L41.568 24 L0 48 Z" fill="white" fill-opacity="0.15" stroke="white" stroke-width="1.5" stroke-linejoin="round"/>
|
||||
<!-- Right face grid cells -->
|
||||
<path d="M0 0 L10.392 -6 L10.392 6 L0 12 Z" fill="white" fill-opacity="0.11"/>
|
||||
<path d="M10.392 -6 L20.784 -12 L20.784 0 L10.392 6 Z" fill="white" fill-opacity="0.05"/>
|
||||
<path d="M20.784 -12 L31.176 -18 L31.176 -6 L20.784 0 Z" fill="white" fill-opacity="0.16"/>
|
||||
<path d="M31.176 -18 L41.568 -24 L41.568 -12 L31.176 -6 Z" fill="white" fill-opacity="0.09"/>
|
||||
<path d="M0 12 L10.392 6 L10.392 18 L0 24 Z" fill="white" fill-opacity="0.18"/>
|
||||
<path d="M10.392 6 L20.784 0 L20.784 12 L10.392 18 Z" fill="white" fill-opacity="0.12"/>
|
||||
<path d="M20.784 0 L31.176 -6 L31.176 6 L20.784 12 Z" fill="white" fill-opacity="0.04"/>
|
||||
<path d="M31.176 -6 L41.568 -12 L41.568 0 L31.176 6 Z" fill="white" fill-opacity="0.14"/>
|
||||
<path d="M0 24 L10.392 18 L10.392 30 L0 36 Z" fill="white" fill-opacity="0.07"/>
|
||||
<path d="M10.392 18 L20.784 12 L20.784 24 L10.392 30 Z" fill="white" fill-opacity="0.19"/>
|
||||
<path d="M20.784 12 L31.176 6 L31.176 18 L20.784 24 Z" fill="white" fill-opacity="0.11"/>
|
||||
<path d="M31.176 6 L41.568 0 L41.568 12 L31.176 18 Z" fill="white" fill-opacity="0.05"/>
|
||||
<path d="M0 36 L10.392 30 L10.392 42 L0 48 Z" fill="white" fill-opacity="0.16"/>
|
||||
<path d="M10.392 30 L20.784 24 L20.784 36 L10.392 42 Z" fill="white" fill-opacity="0.09"/>
|
||||
<path d="M20.784 24 L31.176 18 L31.176 30 L20.784 36 Z" fill="white" fill-opacity="0.14"/>
|
||||
<path d="M31.176 18 L41.568 12 L41.568 24 L31.176 30 Z" fill="white" fill-opacity="0.07"/>
|
||||
<!-- Top face - open -->
|
||||
<path d="M0 -48 L-41.568 -24 L0 0 L41.568 -24 Z" fill="none" stroke="white" stroke-width="1.5" stroke-linejoin="round"/>
|
||||
<!-- OpenCode logo on top face -->
|
||||
<g transform="matrix(0.866, 0.5, -0.866, 0.5, 0, -24) scale(0.75)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M-16 -20 L16 -20 L16 20 L-16 20 Z M-8 -12 L-8 12 L8 12 L8 -12 Z" fill="white"/>
|
||||
<path d="M-8 -4 L8 -4 L8 12 L-8 12 Z" fill="white" fill-opacity="0.4"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 411 B After Width: | Height: | Size: 4.3 KiB |
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { useChatStore } from './stores/chatStore';
|
||||
import { useNavigation } from './hooks/useNavigation';
|
||||
import { OpenChamberLogo } from './components/OpenChamberLogo';
|
||||
|
||||
type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'error';
|
||||
|
||||
@@ -11,9 +12,18 @@ function ConnectionStatusBanner({ status, error, onRetry }: {
|
||||
}) {
|
||||
if (status === 'connected') return null;
|
||||
|
||||
// Show full-screen logo for connecting state
|
||||
if (status === 'connecting') {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-full gap-4">
|
||||
<OpenChamberLogo width={80} height={80} isAnimated />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const messages: Record<ConnectionStatus, string> = {
|
||||
disconnected: 'Not connected to OpenCode API',
|
||||
connecting: 'Connecting...',
|
||||
connecting: '',
|
||||
connected: '',
|
||||
error: error || 'Connection error',
|
||||
};
|
||||
@@ -22,9 +32,6 @@ function ConnectionStatusBanner({ status, error, onRetry }: {
|
||||
<div className={`flex items-center justify-center gap-2 px-4 py-2 text-sm border-b ${
|
||||
status === 'error' ? 'bg-destructive/10 text-destructive' : 'bg-muted text-muted-foreground'
|
||||
}`}>
|
||||
{status === 'connecting' && (
|
||||
<span className="inline-block w-4 h-4 border-2 border-current border-t-transparent rounded-full animate-spin" />
|
||||
)}
|
||||
<span>{messages[status]}</span>
|
||||
{(status === 'disconnected' || status === 'error') && (
|
||||
<button onClick={onRetry} className="px-2 py-0.5 text-xs rounded bg-primary text-primary-foreground hover:bg-primary/90">
|
||||
@@ -265,8 +272,6 @@ export function VSCodeApp() {
|
||||
<div className="flex-1 min-h-0">
|
||||
{currentView === 'sessions' ? (
|
||||
<SessionsList />
|
||||
) : currentView === 'settings' ? (
|
||||
<SettingsView />
|
||||
) : (
|
||||
<ChatPanel />
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
interface OpenChamberLogoProps {
|
||||
className?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
isAnimated?: boolean;
|
||||
}
|
||||
|
||||
// Generate grid cells for a face (4x4 grid)
|
||||
const generateFaceGrid = (
|
||||
topLeft: { x: number; y: number },
|
||||
topRight: { x: number; y: number },
|
||||
bottomRight: { x: number; y: number },
|
||||
bottomLeft: { x: number; y: number },
|
||||
gridSize: number = 4
|
||||
) => {
|
||||
const cells: Array<{ path: string; row: number; col: number }> = [];
|
||||
|
||||
for (let row = 0; row < gridSize; row++) {
|
||||
for (let col = 0; col < gridSize; col++) {
|
||||
const t1 = col / gridSize;
|
||||
const t2 = (col + 1) / gridSize;
|
||||
const s1 = row / gridSize;
|
||||
const s2 = (row + 1) / gridSize;
|
||||
|
||||
const lerp = (a: number, b: number, t: number) => a + (b - a) * t;
|
||||
const bilinear = (tl: number, tr: number, br: number, bl: number, t: number, s: number) => {
|
||||
const top = lerp(tl, tr, t);
|
||||
const bottom = lerp(bl, br, t);
|
||||
return lerp(top, bottom, s);
|
||||
};
|
||||
|
||||
const p1 = {
|
||||
x: bilinear(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x, t1, s1),
|
||||
y: bilinear(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y, t1, s1),
|
||||
};
|
||||
const p2 = {
|
||||
x: bilinear(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x, t2, s1),
|
||||
y: bilinear(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y, t2, s1),
|
||||
};
|
||||
const p3 = {
|
||||
x: bilinear(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x, t2, s2),
|
||||
y: bilinear(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y, t2, s2),
|
||||
};
|
||||
const p4 = {
|
||||
x: bilinear(topLeft.x, topRight.x, bottomRight.x, bottomLeft.x, t1, s2),
|
||||
y: bilinear(topLeft.y, topRight.y, bottomRight.y, bottomLeft.y, t1, s2),
|
||||
};
|
||||
|
||||
cells.push({
|
||||
path: `M${p1.x} ${p1.y} L${p2.x} ${p2.y} L${p3.x} ${p3.y} L${p4.x} ${p4.y} Z`,
|
||||
row,
|
||||
col,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return cells;
|
||||
};
|
||||
|
||||
export const OpenChamberLogo: React.FC<OpenChamberLogoProps> = ({
|
||||
className = '',
|
||||
width = 70,
|
||||
height = 70,
|
||||
isAnimated = false,
|
||||
}) => {
|
||||
// VSCode uses CSS variables for theming
|
||||
const strokeColor = 'var(--vscode-foreground)';
|
||||
const fillColor = 'var(--vscode-foreground)';
|
||||
const logoFillColor = 'var(--vscode-foreground)';
|
||||
const cellHighlightColor = 'var(--vscode-foreground)';
|
||||
|
||||
// Isometric cube geometry
|
||||
const edge = 48;
|
||||
const cos30 = 0.866;
|
||||
const sin30 = 0.5;
|
||||
const centerY = 50;
|
||||
|
||||
const top = { x: 50, y: centerY - edge };
|
||||
const left = { x: 50 - edge * cos30, y: centerY - edge * sin30 };
|
||||
const right = { x: 50 + edge * cos30, y: centerY - edge * sin30 };
|
||||
const center = { x: 50, y: centerY };
|
||||
const bottomLeft = { x: 50 - edge * cos30, y: centerY + edge * sin30 };
|
||||
const bottomRight = { x: 50 + edge * cos30, y: centerY + edge * sin30 };
|
||||
const bottom = { x: 50, y: centerY + edge };
|
||||
|
||||
const topFaceCenterY = (top.y + left.y + center.y + right.y) / 4;
|
||||
const isoMatrix = `matrix(0.866, 0.5, -0.866, 0.5, 50, ${topFaceCenterY})`;
|
||||
|
||||
const leftFaceCells = generateFaceGrid(left, center, bottom, bottomLeft);
|
||||
const rightFaceCells = generateFaceGrid(center, right, bottomRight, bottom);
|
||||
|
||||
const cellOpacities = useMemo(() => {
|
||||
const opacities: number[] = [];
|
||||
for (let i = 0; i < 32; i++) {
|
||||
opacities.push(0.1 + Math.random() * 0.5);
|
||||
}
|
||||
return opacities;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<svg
|
||||
width={width}
|
||||
height={height}
|
||||
viewBox="0 0 100 100"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
role="img"
|
||||
aria-label="OpenChamber logo"
|
||||
>
|
||||
{/* Left face */}
|
||||
<path
|
||||
d={`M${center.x} ${center.y} L${left.x} ${left.y} L${bottomLeft.x} ${bottomLeft.y} L${bottom.x} ${bottom.y} Z`}
|
||||
fill={fillColor}
|
||||
fillOpacity="0.15"
|
||||
stroke={strokeColor}
|
||||
strokeWidth="2"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
|
||||
{/* Left face grid cells */}
|
||||
{leftFaceCells.map((cell, i) => (
|
||||
<path
|
||||
key={`left-${i}`}
|
||||
d={cell.path}
|
||||
fill={cellHighlightColor}
|
||||
fillOpacity={0.35 * cellOpacities[i]}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Right face */}
|
||||
<path
|
||||
d={`M${center.x} ${center.y} L${right.x} ${right.y} L${bottomRight.x} ${bottomRight.y} L${bottom.x} ${bottom.y} Z`}
|
||||
fill={fillColor}
|
||||
fillOpacity="0.15"
|
||||
stroke={strokeColor}
|
||||
strokeWidth="2"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
|
||||
{/* Right face grid cells */}
|
||||
{rightFaceCells.map((cell, i) => (
|
||||
<path
|
||||
key={`right-${i}`}
|
||||
d={cell.path}
|
||||
fill={cellHighlightColor}
|
||||
fillOpacity={0.35 * cellOpacities[i + 16]}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Top face - open */}
|
||||
<path
|
||||
d={`M${top.x} ${top.y} L${left.x} ${left.y} L${center.x} ${center.y} L${right.x} ${right.y} Z`}
|
||||
fill="none"
|
||||
stroke={strokeColor}
|
||||
strokeWidth="2"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
|
||||
{/* OpenCode logo on top face */}
|
||||
<g opacity={isAnimated ? undefined : 1}>
|
||||
{isAnimated && (
|
||||
<animate
|
||||
attributeName="opacity"
|
||||
values="0.4;1;0.4"
|
||||
dur="3s"
|
||||
repeatCount="indefinite"
|
||||
calcMode="spline"
|
||||
keySplines="0.4 0 0.6 1; 0.4 0 0.6 1"
|
||||
/>
|
||||
)}
|
||||
<g transform={`${isoMatrix} scale(0.75)`}>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M-16 -20 L16 -20 L16 20 L-16 20 Z M-8 -12 L-8 12 L8 12 L8 -12 Z"
|
||||
fill={logoFillColor}
|
||||
/>
|
||||
<path
|
||||
d="M-8 -4 L8 -4 L8 12 L-8 12 Z"
|
||||
fill={logoFillColor}
|
||||
fillOpacity="0.4"
|
||||
/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default OpenChamberLogo;
|
||||
Reference in New Issue
Block a user