design(preview): match toggle button sizes to device toggles

This commit is contained in:
2026-06-12 15:00:40 -07:00
parent 6687b79bfd
commit 960232e525
8 changed files with 771 additions and 2127 deletions

View File

@@ -18,8 +18,12 @@ import {
ChevronDown,
ChevronRight,
Users,
HardDrive,
Blocks,
} from "lucide-react";
import { useAnatomy } from "@/components/project/use-anatomy";
export function DashboardSidebar({
workspace,
projectId,
@@ -39,23 +43,40 @@ export function DashboardSidebar({
Record<string, boolean>
>({
settings: true,
data: true,
});
const [searchQuery, setSearchQuery] = useState("");
const { anatomy } = useAnatomy(projectId);
const databases = anatomy?.infrastructure?.databases ?? [];
if (isPreview) {
return <>{children}</>;
}
const toggleSection = (section: string) => {
setExpandedSections((prev) => ({ ...prev, [section]: !prev[section] }));
const handleSectionClick = (segment: string) => {
if (!expandedSections[segment]) {
setExpandedSections((prev) => ({ ...prev, [segment]: true }));
}
};
const menuItems = [
{ segment: "overview", label: "Overview", Icon: LayoutGrid },
{ segment: "plan", label: "Plan & Specs", Icon: ClipboardList },
{ segment: "code", label: "Code", Icon: Code2 },
{ segment: "data", label: "Data", Icon: Database },
{
segment: "data",
label: "Data",
Icon: Database,
hasChildren: true,
children: databases.map((db) => ({
segment: `data/tables?db=${db.uuid}`,
label: db.name,
})),
},
{ segment: "storage", label: "Storage", Icon: HardDrive },
{ segment: "services", label: "Services", Icon: Blocks },
{ segment: "users", label: "Auth / Users", Icon: Users },
{ segment: "integrations", label: "Integrations", Icon: Plug },
{ segment: "security", label: "Security", Icon: ShieldCheck },
@@ -67,6 +88,17 @@ export function DashboardSidebar({
Icon: BarChart2,
badge: "Soon",
},
{
segment: "marketing",
label: "Marketing",
Icon: BarChart2,
badge: "New",
hasChildren: true,
children: [
{ segment: "marketing/seo", label: "SEO & GEO" },
{ segment: "marketing/social", label: "Social content" },
],
},
{
segment: "settings",
label: "Settings",
@@ -170,9 +202,10 @@ export function DashboardSidebar({
}}
onClick={() => {
if (item.hasChildren) {
toggleSection(item.segment);
} else {
// Navigate via link logic would happen here, we'll wrap the icon/label in a link
setExpandedSections((prev) => ({
...prev,
[item.segment]: !prev[item.segment],
}));
}
}}
>
@@ -245,28 +278,41 @@ export function DashboardSidebar({
}}
>
{item.children.map((child) => {
const isChildActive =
pathname === `${projectBase}/${child.segment}`;
const href = child.segment.includes("?")
? `${projectBase}/${child.segment.split("?")[0]}?${child.segment.split("?")[1]}`
: `${projectBase}/${child.segment}`;
let isChildActive = false;
if (child.segment.includes("?")) {
const [basePath, searchStr] = child.segment.split("?");
isChildActive =
pathname === `${projectBase}/${basePath}` &&
(typeof window !== "undefined"
? window.location.search.includes(searchStr)
: false);
} else {
isChildActive =
pathname === `${projectBase}/${child.segment}`;
}
return (
<Link
key={child.segment}
href={`${projectBase}/${child.segment}`}
href={href}
style={{
display: "flex",
alignItems: "center",
padding: "6px 10px 6px 36px",
borderRadius: 8,
padding: "6px 10px 6px 14px",
marginLeft: "18px",
borderRadius: "0 8px 8px 0",
fontSize: "0.8rem",
fontWeight: 500,
textDecoration: "none",
color: isChildActive ? "#18181b" : "#52525b",
background: isChildActive
? "#f4f4f5"
: "transparent",
background: "transparent",
transition: "all 0.1s ease",
border: isChildActive
? "1px solid #e4e4e7"
: "1px solid transparent",
borderLeft: isChildActive
? "2px solid #18181b"
: "2px solid transparent",
}}
>
{child.label}

View File

@@ -37,6 +37,9 @@ export function ProjectIconRail({ workspace, projectId, actions }: Props) {
fontSize: "0.75rem",
fontWeight: 500,
borderRadius: 6,
display: "flex",
alignItems: "center",
height: 24, // Explicitly match device toggles height
textDecoration: "none",
background: isPreviewActive ? "#ffffff" : "transparent",
color: isPreviewActive ? "#18181b" : "#71717a",
@@ -53,6 +56,9 @@ export function ProjectIconRail({ workspace, projectId, actions }: Props) {
fontSize: "0.75rem",
fontWeight: 500,
borderRadius: 6,
display: "flex",
alignItems: "center",
height: 24, // Explicitly match device toggles height
textDecoration: "none",
background: !isPreviewActive ? "#ffffff" : "transparent",
color: !isPreviewActive ? "#18181b" : "#71717a",
@@ -401,12 +407,11 @@ const bar: React.CSSProperties = {
alignItems: "center",
flex: 1,
minWidth: 0,
height: "56px", // Explicitly set height
height: "100%", // Inherit height from parent
padding: "0 16px",
gap: 12,
boxSizing: "border-box",
background: "#fafafa",
borderBottom: "1px solid #e4e4e7",
background: "#faf8f5",
fontFamily: '"Outfit", "Inter", ui-sans-serif, sans-serif',
};

View File

@@ -1027,16 +1027,11 @@ export function ChatPanel({
);
const [showThreads, setShowThreads] = useState(false);
const [mcpToken, setMcpToken] = useState<string | null>(null);
const [isChatMinimized, setIsChatMinimized] = useState<boolean>(() => {
if (typeof window === "undefined") return false;
return !window.location.pathname.includes("/preview");
});
const [isChatMinimized, setIsChatMinimized] = useState<boolean>(false);
// Auto-minimize when navigating to dashboard, auto-open when navigating to preview
useEffect(() => {
if (typeof window !== "undefined") {
setIsChatMinimized(!window.location.pathname.includes("/preview"));
}
setIsChatMinimized(!pathname.includes("/preview"));
}, [pathname]);
const messagesEndRef = useRef<HTMLDivElement>(null);
@@ -2101,12 +2096,9 @@ export function ChatPanel({
}}
onInput={(e) => {
const el = e.currentTarget;
const newlines = (el.value.match(/\n/g) || []).length;
if ((el as any).lastNewlines !== newlines) {
(el as any).lastNewlines = newlines;
el.style.height = "auto";
el.style.height = Math.min(el.scrollHeight, 240) + "px";
}
// Only resize if height actually changed
el.style.height = "auto";
el.style.height = Math.min(el.scrollHeight, 240) + "px";
}}
/>
<div
@@ -2332,7 +2324,7 @@ export function ChatPanel({
alignItems: "stretch",
flexShrink: 0,
height: 48,
borderBottom: "1px solid #e8e4dc",
borderBottom: "1px solid #e4e4e7",
background: "#faf8f5",
boxSizing: "border-box",
}}
@@ -2347,7 +2339,7 @@ export function ChatPanel({
padding: "0 12px",
gap: 6,
boxSizing: "border-box",
borderRight: "1px solid #e8e4dc",
borderRight: "1px solid #e4e4e7",
}}
>
<div