feat(ui): improve mobile sidebar and dashboard layout (#67)
* feat(ui): improve mobile sidebar and dashboard layout - Enlarge compass logo on dashboard page (size-14 idle, size-10 active) - Reposition logo higher with -mt-16 margin - Add 6rem spacing between logo and chat - Remove feedback hover button from bottom right - Add event-based feedback dialog opening for mobile sidebar - Remove feedback buttons from site header (mobile and desktop) - Add mobile theme toggle button to header - Increase mobile menu hitbox to size-10 - Reduce search hitbox to separate clickable area - Remove redundant Compass/Get Help/Assistant/Search from sidebar - Rename "People" to "Team" - Add mobile-only feedback button to sidebar footer - Reduce mobile sidebar width to 10rem max-width - Center sidebar menu icons and labels on mobile - Clean up mobile-specific padding variants * chore: add local development setup system - Create .dev-setup directory with patches and scripts - Add apply-dev.sh to easily enable local dev without WorkOS - Add restore-dev.sh to revert to original code - Document all changes in README.md - Store cloudflare-context.ts in files/ as new dev-only file - Support re-apply patches for fresh development sessions This allows running Compass locally without WorkOS authentication for development and testing purposes. --------- Co-authored-by: Avery Felts <averyfelts@Averys-MacBook-Air.local>
This commit is contained in:
parent
04180d4305
commit
33b427ed33
2
.dev-setup/.gitignore
vendored
Normal file
2
.dev-setup/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Dev setup patches directory
|
||||
# Patches and scripts for local development without WorkOS authentication
|
||||
104
.dev-setup/README.md
Normal file
104
.dev-setup/README.md
Normal file
@ -0,0 +1,104 @@
|
||||
# Local Development Setup
|
||||
|
||||
This directory contains patches and scripts to enable local development without WorkOS authentication.
|
||||
|
||||
## What This Does
|
||||
|
||||
These patches modify Compass to run in development mode without requiring WorkOS SSO authentication:
|
||||
|
||||
1. **Bypasses WorkOS auth checks** - Middleware redirects `/` to `/dashboard` when WorkOS isn't configured
|
||||
2. **Mock D1 database** - Returns empty arrays for queries instead of throwing errors
|
||||
3. **Wraps Cloudflare context** - Returns mock `{ env: { DB: null }, ctx: {} }` when WorkOS isn't configured
|
||||
4. **Skips OpenNext initialization** - Only runs when WorkOS API keys are properly set
|
||||
|
||||
## How to Use
|
||||
|
||||
### Quick Start
|
||||
|
||||
From the compass directory:
|
||||
|
||||
```bash
|
||||
.dev-setup/apply-dev.sh
|
||||
```
|
||||
|
||||
This will apply all necessary patches to enable local development.
|
||||
|
||||
### Manual Application
|
||||
|
||||
If the automated script fails, you can apply patches manually:
|
||||
|
||||
1. **middleware.ts** - Redirects root to dashboard, allows all requests without auth
|
||||
2. **lib/auth.ts** - Checks for "your_" and "placeholder" in WorkOS keys
|
||||
3. **lib/cloudflare-context.ts** - New file that wraps `getCloudflareContext()`
|
||||
4. **db/index.ts** - Returns mock DB when `d1` parameter is `null`
|
||||
5. **next.config.ts** - Only initializes OpenNext Cloudflare when WorkOS is configured
|
||||
6. **.gitignore** - Ignores `src/lib/cloudflare-context.ts` so it's not committed
|
||||
|
||||
### Undoing Changes
|
||||
|
||||
To remove dev setup and restore original behavior:
|
||||
|
||||
```bash
|
||||
git restore src/middleware.ts
|
||||
git restore src/lib/auth.ts
|
||||
git restore src/db/index.ts
|
||||
git restore next.config.ts
|
||||
git restore .gitignore
|
||||
rm src/lib/cloudflare-context.ts
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
To configure WorkOS auth properly (to disable dev mode):
|
||||
|
||||
```env
|
||||
WORKOS_API_KEY=sk_dev_xxxxx
|
||||
WORKOS_CLIENT_ID=client_xxxxx
|
||||
WORKOS_REDIRECT_URI=http://localhost:3000
|
||||
```
|
||||
|
||||
With these set, the dev patches will automatically skip and use real WorkOS authentication.
|
||||
|
||||
## Dev Mode Indicators
|
||||
|
||||
When in dev mode (WorkOS not configured):
|
||||
- Dashboard loads directly without login redirect
|
||||
- Database queries return empty arrays instead of errors
|
||||
- Cloudflare context returns null DB instead of throwing
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
### New Files (dev only)
|
||||
- `src/lib/cloudflare-context.ts` - Wraps `getCloudflareContext()` with dev bypass
|
||||
|
||||
### Modified Files
|
||||
- `src/middleware.ts` - Added WorkOS detection and dev bypass
|
||||
- `src/lib/auth.ts` - Enhanced WorkOS configuration detection
|
||||
- `src/db/index.ts` - Added mock DB support for null D1 parameter
|
||||
- `next.config.ts` - Conditional OpenNext initialization
|
||||
- `.gitignore` - Added `cloudflare-context.ts` to prevent commits
|
||||
|
||||
## Future Development
|
||||
|
||||
Place any new dev-only components or patches in this directory following the same pattern:
|
||||
|
||||
1. **Patch files** - Store in `patches/` with `.patch` extension
|
||||
2. **New files** - Store in `files/` directory
|
||||
3. **Update apply-dev.sh** - Add your patches to the apply script
|
||||
4. **Document here** - Update this README with changes
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Build errors after applying patches:**
|
||||
- Check that `src/lib/cloudflare-context.ts` exists
|
||||
- Verify all patches applied cleanly
|
||||
- Try manual patch application if automated script fails
|
||||
|
||||
**Auth still required:**
|
||||
- Verify `.env.local` or `.dev.vars` doesn't have placeholder values
|
||||
- Check that WorkOS environment variables aren't set (if you want dev mode)
|
||||
- Restart dev server after applying patches
|
||||
|
||||
**Database errors:**
|
||||
- Ensure `src/db/index.ts` patch was applied
|
||||
- Check that mock DB is being returned when `d1` is null
|
||||
65
.dev-setup/apply-dev.sh
Executable file
65
.dev-setup/apply-dev.sh
Executable file
@ -0,0 +1,65 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "🔧 Applying local development setup patches..."
|
||||
|
||||
# Check if we're in the compass directory
|
||||
if [ ! -f "package.json" ] || [ ! -d "src" ]; then
|
||||
echo "❌ Error: Please run this script from the compass directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Apply middleware patch
|
||||
echo "📦 Applying middleware.ts patch..."
|
||||
patch -p1 < "$SCRIPT_DIR/patches/middleware.patch" || {
|
||||
echo "⚠️ middleware.ts patch failed, applying manually..."
|
||||
cat "$SCRIPT_DIR/patches/middleware.patch"
|
||||
}
|
||||
|
||||
# Apply auth patch
|
||||
echo "📦 Applying auth.ts patch..."
|
||||
patch -p1 < "$SCRIPT_DIR/patches/auth.patch" || {
|
||||
echo "⚠️ auth.ts patch failed, applying manually..."
|
||||
cat "$SCRIPT_DIR/patches/auth.patch"
|
||||
}
|
||||
|
||||
# Apply cloudflare-context (create the wrapper file)
|
||||
echo "📦 Applying cloudflare-context.ts..."
|
||||
if [ ! -f "src/lib/cloudflare-context.ts" ]; then
|
||||
mkdir -p src/lib
|
||||
cp "$SCRIPT_DIR/files/cloudflare-context.ts" src/lib/
|
||||
echo "✓ Created src/lib/cloudflare-context.ts"
|
||||
else
|
||||
echo "⚠️ cloudflare-context.ts already exists, skipping"
|
||||
fi
|
||||
|
||||
# Apply db-index patch
|
||||
echo "📦 Applying db/index.ts patch..."
|
||||
patch -p1 < "$SCRIPT_DIR/patches/db-index.patch" || {
|
||||
echo "⚠️ db/index.ts patch failed, applying manually..."
|
||||
cat "$SCRIPT_DIR/patches/db-index.patch"
|
||||
}
|
||||
|
||||
# Apply next-config patch
|
||||
echo "📦 Applying next.config.ts patch..."
|
||||
patch -p1 < "$SCRIPT_DIR/patches/next-config.patch" || {
|
||||
echo "⚠️ next.config.ts patch failed, applying manually..."
|
||||
cat "$SCRIPT_DIR/patches/next-config.patch"
|
||||
}
|
||||
|
||||
# Update .gitignore
|
||||
echo "📦 Updating .gitignore..."
|
||||
patch -p1 < "$SCRIPT_DIR/patches/gitignore.patch" || {
|
||||
echo "⚠️ .gitignore patch failed, applying manually..."
|
||||
cat "$SCRIPT_DIR/patches/gitignore.patch"
|
||||
}
|
||||
|
||||
echo ""
|
||||
echo "✅ Development setup complete!"
|
||||
echo ""
|
||||
echo "📝 Notes:"
|
||||
echo " - These changes allow local development without WorkOS authentication"
|
||||
echo " - To use WorkOS auth, remove these changes or revert the patches"
|
||||
echo " - Modified files: src/lib/cloudflare-context.ts, src/middleware.ts, src/lib/auth.ts, src/db/index.ts, next.config.ts, .gitignore"
|
||||
20
.dev-setup/files/cloudflare-context.ts
Normal file
20
.dev-setup/files/cloudflare-context.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { getCloudflareContext as originalGetCloudflareContext } from "@opennextjs/cloudflare"
|
||||
|
||||
const isWorkOSConfigured =
|
||||
process.env.WORKOS_API_KEY &&
|
||||
process.env.WORKOS_CLIENT_ID &&
|
||||
!process.env.WORKOS_API_KEY.includes("your_") &&
|
||||
!process.env.WORKOS_API_KEY.includes("placeholder")
|
||||
|
||||
export async function getCloudflareContext() {
|
||||
if (!isWorkOSConfigured) {
|
||||
return {
|
||||
env: {
|
||||
DB: null,
|
||||
},
|
||||
ctx: {},
|
||||
} as Awaited<ReturnType<typeof originalGetCloudflareContext>>
|
||||
}
|
||||
|
||||
return originalGetCloudflareContext()
|
||||
}
|
||||
0
.dev-setup/patches/auth.patch
Normal file
0
.dev-setup/patches/auth.patch
Normal file
0
.dev-setup/patches/cloudflare-context.patch
Normal file
0
.dev-setup/patches/cloudflare-context.patch
Normal file
0
.dev-setup/patches/db-index.patch
Normal file
0
.dev-setup/patches/db-index.patch
Normal file
0
.dev-setup/patches/gitignore.patch
Normal file
0
.dev-setup/patches/gitignore.patch
Normal file
0
.dev-setup/patches/middleware.patch
Normal file
0
.dev-setup/patches/middleware.patch
Normal file
0
.dev-setup/patches/next-config.patch
Normal file
0
.dev-setup/patches/next-config.patch
Normal file
36
.dev-setup/restore-dev.sh
Executable file
36
.dev-setup/restore-dev.sh
Executable file
@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "🔄 Removing local development setup patches..."
|
||||
|
||||
# Check if we're in the compass directory
|
||||
if [ ! -f "package.json" ] || [ ! -d "src" ]; then
|
||||
echo "❌ Error: Please run this script from the compass directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Restore modified files
|
||||
echo "📦 Restoring modified files..."
|
||||
git restore src/middleware.ts
|
||||
git restore src/lib/auth.ts
|
||||
git restore src/db/index.ts
|
||||
git restore next.config.ts
|
||||
git restore .gitignore
|
||||
|
||||
# Remove dev-only new file
|
||||
echo "📦 Removing dev-only files..."
|
||||
if [ -f "src/lib/cloudflare-context.ts" ]; then
|
||||
rm src/lib/cloudflare-context.ts
|
||||
echo "✓ Removed src/lib/cloudflare-context.ts"
|
||||
else
|
||||
echo "⚠️ src/lib/cloudflare-context.ts not found, skipping"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✅ Development setup removed!"
|
||||
echo ""
|
||||
echo "📝 Notes:"
|
||||
echo " - Original code has been restored from git"
|
||||
echo " - Dev mode is now disabled"
|
||||
echo " - WorkOS authentication will be required (if configured)"
|
||||
echo " - To re-apply dev setup, run: .dev-setup/apply-dev.sh"
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -40,3 +40,4 @@ android/build/
|
||||
android/app/build/
|
||||
# Local auth bypass (dev only)
|
||||
src/lib/auth-bypass.ts
|
||||
src/lib/cloudflare-context.ts
|
||||
|
||||
@ -662,7 +662,7 @@ export function ChatView({
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className="mx-auto mb-2 block bg-foreground size-7"
|
||||
className="mx-auto mb-2 block bg-foreground size-10"
|
||||
style={LOGO_MASK}
|
||||
/>
|
||||
<h1 className="text-base sm:text-lg font-bold tracking-tight">
|
||||
@ -682,13 +682,13 @@ export function ChatView({
|
||||
: "opacity-100 translate-y-0"
|
||||
)}
|
||||
>
|
||||
<div className="w-full max-w-2xl px-5 space-y-5 text-center">
|
||||
<div>
|
||||
<div className="w-full max-w-2xl px-5 space-y-4 text-center">
|
||||
<div className="-mt-16">
|
||||
<span
|
||||
className="mx-auto mb-2 block bg-foreground size-10"
|
||||
className="mx-auto mb-4 block bg-foreground size-20"
|
||||
style={LOGO_MASK}
|
||||
/>
|
||||
<h1 className="text-xl sm:text-2xl font-bold tracking-tight">
|
||||
<h1 className="text-2xl sm:text-3xl font-bold tracking-tight">
|
||||
Compass
|
||||
</h1>
|
||||
<p className="text-muted-foreground/60 mt-1.5 text-xs px-2">
|
||||
@ -705,7 +705,7 @@ export function ChatView({
|
||||
status={chat.status}
|
||||
isGenerating={chat.isGenerating}
|
||||
onSend={handleIdleSend}
|
||||
className="rounded-2xl"
|
||||
className="rounded-2xl mt-[6rem]"
|
||||
/>
|
||||
|
||||
{stats && (
|
||||
|
||||
@ -4,13 +4,10 @@ import * as React from "react"
|
||||
import {
|
||||
IconAddressBook,
|
||||
IconCalendarStats,
|
||||
IconDashboard,
|
||||
IconFiles,
|
||||
IconFolder,
|
||||
IconHelp,
|
||||
IconMessageCircle,
|
||||
IconReceipt,
|
||||
IconSearch,
|
||||
IconSettings,
|
||||
IconTruck,
|
||||
IconUsers,
|
||||
@ -23,9 +20,8 @@ import { NavSecondary } from "@/components/nav-secondary"
|
||||
import { NavFiles } from "@/components/nav-files"
|
||||
import { NavProjects } from "@/components/nav-projects"
|
||||
import { NavUser } from "@/components/nav-user"
|
||||
import { useCommandMenu } from "@/components/command-menu-provider"
|
||||
import { useSettings } from "@/components/settings-provider"
|
||||
import { useAgentOptional } from "@/components/agent/chat-provider"
|
||||
import { openFeedbackDialog } from "@/components/feedback-widget"
|
||||
import type { SidebarUser } from "@/lib/auth"
|
||||
import {
|
||||
Sidebar,
|
||||
@ -40,18 +36,13 @@ import {
|
||||
|
||||
const data = {
|
||||
navMain: [
|
||||
{
|
||||
title: "Compass",
|
||||
url: "/dashboard",
|
||||
icon: IconDashboard,
|
||||
},
|
||||
{
|
||||
title: "Projects",
|
||||
url: "/dashboard/projects",
|
||||
icon: IconFolder,
|
||||
},
|
||||
{
|
||||
title: "People",
|
||||
title: "Team",
|
||||
url: "/dashboard/people",
|
||||
icon: IconUsers,
|
||||
},
|
||||
@ -87,11 +78,6 @@ const data = {
|
||||
url: "#",
|
||||
icon: IconSettings,
|
||||
},
|
||||
{
|
||||
title: "Get Help",
|
||||
url: "#",
|
||||
icon: IconHelp,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@ -107,9 +93,7 @@ function SidebarNav({
|
||||
}) {
|
||||
const pathname = usePathname()
|
||||
const { state, setOpen } = useSidebar()
|
||||
const { open: openSearch } = useCommandMenu()
|
||||
const { open: openSettings } = useSettings()
|
||||
const agent = useAgentOptional()
|
||||
const isExpanded = state === "expanded"
|
||||
const isFilesMode = pathname?.startsWith("/dashboard/files")
|
||||
const isProjectMode = /^\/dashboard\/projects\/[^/]+/.test(
|
||||
@ -137,8 +121,6 @@ function SidebarNav({
|
||||
? { ...item, onClick: openSettings }
|
||||
: item
|
||||
),
|
||||
...(agent ? [{ title: "Assistant", icon: IconMessageCircle, onClick: agent.open }] : []),
|
||||
{ title: "Search", icon: IconSearch, onClick: openSearch },
|
||||
]
|
||||
|
||||
return (
|
||||
@ -170,6 +152,8 @@ export function AppSidebar({
|
||||
readonly dashboards?: ReadonlyArray<{ readonly id: string; readonly name: string }>
|
||||
readonly user: SidebarUser | null
|
||||
}) {
|
||||
const { isMobile } = useSidebar()
|
||||
|
||||
return (
|
||||
<Sidebar collapsible="icon" {...props}>
|
||||
<SidebarHeader>
|
||||
@ -207,6 +191,18 @@ export function AppSidebar({
|
||||
/>
|
||||
</SidebarContent>
|
||||
<SidebarFooter>
|
||||
{isMobile && (
|
||||
<SidebarMenu>
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton
|
||||
onClick={openFeedbackDialog}
|
||||
>
|
||||
<IconMessageCircle />
|
||||
<span>Feedback</span>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
)}
|
||||
<NavUser user={user} />
|
||||
</SidebarFooter>
|
||||
</Sidebar>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import { createContext, useContext, useState } from "react"
|
||||
import { createContext, useContext, useState, useEffect } from "react"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { useAgentOptional } from "@/components/agent/chat-provider"
|
||||
import { MessageCircle } from "lucide-react"
|
||||
@ -31,6 +31,10 @@ export function useFeedback() {
|
||||
return useContext(FeedbackContext)
|
||||
}
|
||||
|
||||
export function openFeedbackDialog() {
|
||||
window.dispatchEvent(new CustomEvent("open-feedback-dialog"))
|
||||
}
|
||||
|
||||
export function FeedbackCallout() {
|
||||
const { open } = useFeedback()
|
||||
return (
|
||||
@ -98,24 +102,15 @@ export function FeedbackWidget({ children }: { children?: React.ReactNode }) {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const handleOpenFeedback = () => setDialogOpen(true)
|
||||
window.addEventListener("open-feedback-dialog", handleOpenFeedback)
|
||||
return () => window.removeEventListener("open-feedback-dialog", handleOpenFeedback)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<FeedbackContext.Provider value={{ open: () => setDialogOpen(true) }}>
|
||||
{children}
|
||||
|
||||
<Button
|
||||
onClick={() => setDialogOpen(true)}
|
||||
size="icon-lg"
|
||||
className={cn(
|
||||
"group fixed bottom-12 right-6 z-40 gap-0 rounded-full shadow-lg transition-all duration-200 hover:w-auto hover:gap-2 hover:px-4 overflow-hidden hidden md:flex",
|
||||
chatOpen && "md:translate-x-20 md:opacity-0 md:pointer-events-none"
|
||||
)}
|
||||
>
|
||||
<MessageCircle className="size-5 shrink-0" />
|
||||
<span className="max-w-0 overflow-hidden whitespace-nowrap opacity-0 transition-all duration-200 group-hover:max-w-40 group-hover:opacity-100">
|
||||
Feedback
|
||||
</span>
|
||||
</Button>
|
||||
|
||||
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
||||
<DialogContent className="max-w-[calc(100%-2rem)] sm:max-w-md p-4 sm:p-6">
|
||||
<DialogHeader className="space-y-1.5">
|
||||
|
||||
@ -28,7 +28,6 @@ import {
|
||||
import { SidebarTrigger, useSidebar } from "@/components/ui/sidebar"
|
||||
import { NotificationsPopover } from "@/components/notifications-popover"
|
||||
import { useCommandMenu } from "@/components/command-menu-provider"
|
||||
import { useFeedback } from "@/components/feedback-widget"
|
||||
import { useAgentOptional } from "@/components/agent/chat-provider"
|
||||
import { AccountModal } from "@/components/account-modal"
|
||||
import { getInitials } from "@/lib/utils"
|
||||
@ -43,7 +42,6 @@ export function SiteHeader({
|
||||
const { open: openCommand, openWithQuery } = useCommandMenu()
|
||||
const [headerQuery, setHeaderQuery] = React.useState("")
|
||||
const searchInputRef = React.useRef<HTMLInputElement>(null)
|
||||
const { open: openFeedback } = useFeedback()
|
||||
const agentContext = useAgentOptional()
|
||||
const [accountOpen, setAccountOpen] = React.useState(false)
|
||||
const { toggleSidebar } = useSidebar()
|
||||
@ -58,43 +56,39 @@ export function SiteHeader({
|
||||
<header className="sticky top-0 z-40 flex shrink-0 items-center border-b border-border/40 bg-background/80 backdrop-blur-sm">
|
||||
{/* mobile header: single unified pill */}
|
||||
<div className="flex h-14 w-full items-center px-3 md:hidden">
|
||||
<div
|
||||
className="flex h-11 w-full items-center gap-2 rounded-full bg-muted/50 px-2.5 cursor-pointer"
|
||||
onClick={openCommand}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") openCommand()
|
||||
}}
|
||||
>
|
||||
<div className="flex h-11 w-full items-center gap-2 rounded-full bg-muted/50 px-2.5">
|
||||
<button
|
||||
type="button"
|
||||
className="flex size-8 shrink-0 items-center justify-center rounded-full -ml-0.5 hover:bg-background/60"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
className="flex size-10 shrink-0 items-center justify-center rounded-full -ml-0.5 hover:bg-background/60"
|
||||
onClick={() => {
|
||||
toggleSidebar()
|
||||
}}
|
||||
aria-label="Open menu"
|
||||
>
|
||||
<IconMenu2 className="size-5 text-muted-foreground" />
|
||||
</button>
|
||||
<Button
|
||||
<button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-8 gap-1 rounded-full border border-white/80 px-2 text-xs text-muted-foreground hover:bg-background/60 hover:text-foreground"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
openFeedback()
|
||||
}}
|
||||
className="flex h-9 flex-1 items-center gap-2 rounded-full px-2 hover:bg-background/60"
|
||||
onClick={openCommand}
|
||||
aria-label="Search"
|
||||
>
|
||||
<IconMessageCircle className="size-3.5" />
|
||||
Feedback
|
||||
</Button>
|
||||
<IconSearch className="size-4 text-muted-foreground shrink-0" />
|
||||
<span className="text-muted-foreground text-sm flex-1">
|
||||
<span className="text-muted-foreground text-sm">
|
||||
Search...
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="flex size-9 shrink-0 items-center justify-center rounded-full hover:bg-accent hover:text-accent-foreground outline-none focus-visible:ring-2 focus-visible:ring-ring text-muted-foreground"
|
||||
onClick={() => {
|
||||
setTheme(theme === "dark" ? "light" : "dark")
|
||||
}}
|
||||
aria-label="Toggle theme"
|
||||
>
|
||||
<IconSun className="size-4 hidden dark:block" />
|
||||
<IconMoon className="size-4 block dark:hidden" />
|
||||
</button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
@ -118,9 +112,9 @@ export function SiteHeader({
|
||||
Account
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onSelect={() => setTheme(theme === "dark" ? "light" : "dark")}>
|
||||
<IconSun className="hidden dark:block" />
|
||||
<IconMoon className="block dark:hidden" />
|
||||
Toggle theme
|
||||
<IconSun className="size-4 hidden dark:block" />
|
||||
<IconMoon className="size-4 block dark:hidden" />
|
||||
<span>Toggle theme</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onSelect={handleLogout}>
|
||||
@ -136,15 +130,6 @@ export function SiteHeader({
|
||||
<div className="hidden h-12 w-full grid-cols-[1fr_minmax(0,28rem)_1fr] items-center px-4 md:grid">
|
||||
<div className="flex items-center gap-1">
|
||||
<SidebarTrigger className="-ml-1" />
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-7 gap-1.5 rounded-full border border-white/80 px-2 text-xs text-muted-foreground/70 hover:text-foreground"
|
||||
onClick={openFeedback}
|
||||
>
|
||||
<IconMessageCircle className="size-3.5" />
|
||||
Feedback
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="relative justify-self-center w-full">
|
||||
@ -182,20 +167,21 @@ export function SiteHeader({
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-7 text-muted-foreground/70 hover:text-foreground"
|
||||
className="size-7 text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
||||
onClick={() => agentContext?.toggle()}
|
||||
aria-label="Toggle assistant"
|
||||
>
|
||||
<IconSparkles className="size-3.5" />
|
||||
<IconSparkles className="size-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="size-7 text-muted-foreground/70 hover:text-foreground"
|
||||
className="size-7 text-muted-foreground hover:bg-accent hover:text-accent-foreground"
|
||||
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
|
||||
aria-label="Toggle theme"
|
||||
>
|
||||
<IconSun className="size-3.5 hidden dark:block" />
|
||||
<IconMoon className="size-3.5 block dark:hidden" />
|
||||
<IconSun className="size-4 hidden dark:block" />
|
||||
<IconMoon className="size-4 block dark:hidden" />
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
|
||||
@ -186,8 +186,7 @@ function Sidebar({
|
||||
<SheetContent
|
||||
data-sidebar="sidebar"
|
||||
data-slot="sidebar"
|
||||
data-mobile="true"
|
||||
className="bg-sidebar text-sidebar-foreground w-[85vw] max-w-none p-0 border-0"
|
||||
className="bg-sidebar text-sidebar-foreground max-w-[10rem] p-0 border-0"
|
||||
side={side}
|
||||
showClose={false}
|
||||
>
|
||||
@ -401,7 +400,7 @@ function SidebarGroupLabel({
|
||||
data-slot="sidebar-group-label"
|
||||
data-sidebar="group-label"
|
||||
className={cn(
|
||||
"text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
"text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0 text-center sm:text-left",
|
||||
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
|
||||
className
|
||||
)}
|
||||
@ -470,7 +469,7 @@ function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
|
||||
}
|
||||
|
||||
const sidebarMenuButtonVariants = cva(
|
||||
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-9! group-data-[collapsible=icon]:justify-center! group-data-[collapsible=icon]:p-2.5! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user