Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions src/components/WindowTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { WindowInstance } from "@/types/app";
import { WindowToolbar } from "./WindowToolbar";
import { WindowRenderer } from "./WindowRenderer";
import { useDynamicWindowTitle } from "./DynamicWindowTitle";
import { useGrimoire } from "@/core/state";

interface WindowTileProps {
id: string;
Expand All @@ -13,12 +14,20 @@ interface WindowTileProps {

export function WindowTile({ id, window, path, onClose }: WindowTileProps) {
const { title, icon, tooltip } = useDynamicWindowTitle(window);
const { setWindowBackgroundColor } = useGrimoire();
const Icon = icon;

// Custom toolbar renderer to include icon
const renderToolbar = () => {
return (
<div className="mosaic-window-toolbar draggable flex items-center justify-between w-full">
<div
className="mosaic-window-toolbar draggable flex items-center justify-between w-full transition-colors"
style={
window.backgroundColor
? { backgroundColor: window.backgroundColor + "30" }
: undefined
}
>
<div className="mosaic-window-title flex items-center gap-2 flex-1">
{Icon && (
<span title={tooltip} className="flex-shrink-0">
Expand All @@ -29,7 +38,13 @@ export function WindowTile({ id, window, path, onClose }: WindowTileProps) {
{title}
</span>
</div>
<WindowToolbar onClose={() => onClose(id)} />
<WindowToolbar
onClose={() => onClose(id)}
backgroundColor={window.backgroundColor}
onBackgroundColorChange={(color) =>
setWindowBackgroundColor(id, color)
}
/>
</div>
);
};
Expand Down
72 changes: 68 additions & 4 deletions src/components/WindowToolbar.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,76 @@
import { X } from "lucide-react";
import { X, Palette } from "lucide-react";
import { useState } from "react";

interface WindowToolbarProps {
onClose?: () => void;
backgroundColor?: string;
onBackgroundColorChange?: (color: string) => void;
}

export function WindowToolbar({ onClose }: WindowToolbarProps) {
const COLORS = [
{ label: "Default", value: undefined },
{ label: "Red", value: "#ef4444" },
{ label: "Orange", value: "#f97316" },
{ label: "Yellow", value: "#eab308" },
{ label: "Green", value: "#22c55e" },
{ label: "Cyan", value: "#06b6d4" },
{ label: "Blue", value: "#3b82f6" },
{ label: "Purple", value: "#8b5cf6" },
{ label: "Pink", value: "#ec4899" },
{ label: "Indigo", value: "#6366f1" },
{ label: "Teal", value: "#14b8a6" },
{ label: "Gray", value: "#6b7280" },
];

export function WindowToolbar({
onClose,
backgroundColor,
onBackgroundColorChange,
}: WindowToolbarProps) {
const [showColorPicker, setShowColorPicker] = useState(false);

return (
<>
<div className="flex items-center gap-1">
<div className="relative">
<button
className="p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors"
onClick={() => setShowColorPicker(!showColorPicker)}
title="Change window color"
>
<Palette className="size-4" />
</button>

{showColorPicker && (
<div className="absolute right-0 top-full mt-2 bg-background border border-border rounded-lg shadow-lg p-3 z-50">
<div className="grid grid-cols-4 gap-3">
{COLORS.map((color) => (
<button
key={color.value || "default"}
className="w-8 h-8 rounded border-2 flex items-center justify-center flex-shrink-0 hover:scale-110 transition-transform"
style={{
backgroundColor: color.value || "transparent",
borderColor:
backgroundColor === color.value ? "#fff" : "#ccc",
borderStyle: !color.value ? "dashed" : "solid",
}}
onClick={() => {
onBackgroundColorChange?.(color.value || "");
setShowColorPicker(false);
}}
title={color.label}
>
{!color.value && (
<span className="text-xs font-bold text-muted-foreground">
×
</span>
)}
</button>
))}
</div>
</div>
)}
</div>

{onClose && (
<button
className="p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors"
Expand All @@ -16,6 +80,6 @@ export function WindowToolbar({ onClose }: WindowToolbarProps) {
<X className="size-4" />
</button>
)}
</>
</div>
);
}
25 changes: 25 additions & 0 deletions src/core/logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,28 @@ export const setActiveAccountRelays = (
},
};
};

/**
* Updates the background color of a window.
*/
export const setWindowBackgroundColor = (
state: GrimoireState,
windowId: string,
backgroundColor: string,
): GrimoireState => {
const window = state.windows[windowId];
if (!window) {
return state;
}

return {
...state,
windows: {
...state.windows,
[windowId]: {
...window,
backgroundColor,
},
},
};
};
4 changes: 4 additions & 0 deletions src/core/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,9 @@ export const useGrimoire = () => {
setState((prev) => Logic.setActiveAccount(prev, pubkey)),
setActiveAccountRelays: (relays: any) =>
setState((prev) => Logic.setActiveAccountRelays(prev, relays)),
setWindowBackgroundColor: (windowId: string, backgroundColor: string) =>
setState((prev) =>
Logic.setWindowBackgroundColor(prev, windowId, backgroundColor),
),
};
};
1 change: 1 addition & 0 deletions src/types/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface WindowInstance {
appId: AppId;
title: string;
props: any;
backgroundColor?: string;
}

export interface Workspace {
Expand Down