diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png index 085652c..042c5a4 100755 Binary files a/public/apple-touch-icon.png and b/public/apple-touch-icon.png differ diff --git a/public/favicon.png b/public/favicon.png index c430b05..b5b00b9 100755 Binary files a/public/favicon.png and b/public/favicon.png differ diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 5d02047..29c8bc4 100755 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -1,13 +1,79 @@ import { Button } from "@/components/ui/button" -import { IconExternalLink } from "@tabler/icons-react" +import { + IconBrandGithub, + IconExternalLink, + IconGitCommit, + IconGitFork, + IconStar, + IconAlertCircle, + IconEye, +} from "@tabler/icons-react" -const GITHUB_URL = - "https://github.com/High-Performance-Structures/compass" +const REPO = "High-Performance-Structures/compass" +const GITHUB_URL = `https://github.com/${REPO}` + +type RepoStats = { + stargazers_count: number + forks_count: number + open_issues_count: number + subscribers_count: number +} + +type Commit = { + sha: string + commit: { + message: string + author: { name: string; date: string } + } + html_url: string +} + +async function getRepoData() { + try { + const [repoRes, commitsRes] = await Promise.all([ + fetch(`https://api.github.com/repos/${REPO}`, { + next: { revalidate: 300 }, + headers: { Accept: "application/vnd.github+json" }, + }), + fetch(`https://api.github.com/repos/${REPO}/commits?per_page=8`, { + next: { revalidate: 300 }, + headers: { Accept: "application/vnd.github+json" }, + }), + ]) + + if (!repoRes.ok || !commitsRes.ok) return null + + const repo: RepoStats = await repoRes.json() + const commits: Commit[] = await commitsRes.json() + return { repo, commits } + } catch { + return null + } +} + +function timeAgo(date: string) { + const seconds = Math.floor( + (Date.now() - new Date(date).getTime()) / 1000 + ) + if (seconds < 60) return "just now" + const minutes = Math.floor(seconds / 60) + if (minutes < 60) return `${minutes}m ago` + const hours = Math.floor(minutes / 60) + if (hours < 24) return `${hours}h ago` + const days = Math.floor(hours / 24) + if (days < 30) return `${days}d ago` + return new Date(date).toLocaleDateString("en-US", { + month: "short", + day: "numeric", + }) +} + +export default async function Page() { + const data = await getRepoData() -export default function Page() { return (
-
+
-
-
-

- - Working -

-
    -
  • Projects — create and manage projects with D1 database
  • -
  • Schedule — Gantt chart with phases, tasks, dependencies, and critical path
  • -
  • File browser — drive-style UI with folder navigation
  • -
  • Settings — app preferences with theme and notifications
  • -
  • Sidebar navigation with contextual project/file views
  • -
  • Command palette search (Cmd+K)
  • -
-
+
+
+
+

+ + Working +

+
    +
  • Projects — create and manage projects with D1 database
  • +
  • Schedule — Gantt chart with phases, tasks, dependencies, and critical path
  • +
  • File browser — drive-style UI with folder navigation
  • +
  • Settings — app preferences with theme and notifications
  • +
  • Sidebar navigation with contextual project/file views
  • +
  • Command palette search (Cmd+K)
  • +
+
-
-

- - In Progress -

-
    -
  • Project auto-provisioning (code generation, CSI folder structure)
  • -
  • Budget tracking (CSI divisions, estimated vs actual, change orders)
  • -
  • Document management (S3/R2 storage, metadata, versioning)
  • -
  • Communication logging (manual entries, timeline view)
  • -
  • Dashboard — three-column layout (past due, due today, action items)
  • -
  • User authentication and roles (WorkOS)
  • -
  • Email notifications (Resend)
  • -
  • Basic reports (budget variance, overdue tasks, monthly actuals)
  • -
-
+
+

+ + In Progress +

+
    +
  • Project auto-provisioning (code generation, CSI folder structure)
  • +
  • Budget tracking (CSI divisions, estimated vs actual, change orders)
  • +
  • Document management (S3/R2 storage, metadata, versioning)
  • +
  • Communication logging (manual entries, timeline view)
  • +
  • Dashboard — three-column layout (past due, due today, action items)
  • +
  • User authentication and roles (WorkOS)
  • +
  • Email notifications (Resend)
  • +
  • Basic reports (budget variance, overdue tasks, monthly actuals)
  • +
+
-
-

- - Planned -

-
    -
  • Client portal with read-only views
  • -
  • BuilderTrend import wizard (CSV-based)
  • -
  • Daily logs
  • -
  • Time tracking
  • -
  • Report builder (custom fields and filters)
  • -
  • Bid package management
  • -
-
+
+

+ + Planned +

+
    +
  • Client portal with read-only views
  • +
  • BuilderTrend import wizard (CSV-based)
  • +
  • Daily logs
  • +
  • Time tracking
  • +
  • Report builder (custom fields and filters)
  • +
  • Bid package management
  • +
+
-
-

- - Future -

-
    -
  • Netsuite/QuickBooks API sync
  • -
  • Payment integration
  • -
  • RFI/Submittal tracking
  • -
  • Native mobile apps (iOS/Android)
  • -
  • Advanced scheduling (resource leveling, baseline comparison)
  • -
-
-
+
+

+ + Future +

+
    +
  • Netsuite/QuickBooks API sync
  • +
  • Payment integration
  • +
  • RFI/Submittal tracking
  • +
  • Native mobile apps (iOS/Android)
  • +
  • Advanced scheduling (resource leveling, baseline comparison)
  • +
+
- + + {data && ( +
+ + +
+

View on GitHub

+

{REPO}

+
+ +
+
+ } + label="Stars" + value={data.repo.stargazers_count} + /> + } + label="Forks" + value={data.repo.forks_count} + /> + } + label="Issues" + value={data.repo.open_issues_count} + /> + } + label="Watchers" + value={data.repo.subscribers_count} + /> +
+ + +
+ )}
) } + +function StatCard({ + icon, + label, + value, +}: { + icon: React.ReactNode + label: string + value: number +}) { + return ( +
+
+ {icon} + {label} +
+

+ {value.toLocaleString()} +

+
+ ) +} diff --git a/src/components/app-sidebar.tsx b/src/components/app-sidebar.tsx index 8959d6d..23cd6dc 100755 --- a/src/components/app-sidebar.tsx +++ b/src/components/app-sidebar.tsx @@ -78,7 +78,7 @@ function SidebarNav({ projects: { id: string; name: string }[] }) { const pathname = usePathname() - const { state } = useSidebar() + const { state, setOpen } = useSidebar() const { open: openSearch } = useCommandMenu() const { open: openSettings } = useSettings() const isExpanded = state === "expanded" @@ -86,6 +86,13 @@ function SidebarNav({ const isProjectMode = /^\/dashboard\/projects\/[^/]+/.test( pathname ?? "" ) + + React.useEffect(() => { + if ((isFilesMode || isProjectMode) && !isExpanded) { + setOpen(true) + } + }, [isFilesMode, isProjectMode, isExpanded, setOpen]) + const showContext = isExpanded && (isFilesMode || isProjectMode) const mode = showContext && isFilesMode diff --git a/src/components/files/storage-indicator.tsx b/src/components/files/storage-indicator.tsx index 6ba9f7d..917354d 100755 --- a/src/components/files/storage-indicator.tsx +++ b/src/components/files/storage-indicator.tsx @@ -1,6 +1,5 @@ "use client" -import { Progress } from "@/components/ui/progress" import { formatFileSize } from "@/lib/file-utils" import type { StorageUsage } from "@/lib/files-data" @@ -8,14 +7,15 @@ export function StorageIndicator({ usage }: { usage: StorageUsage }) { const percent = Math.round((usage.used / usage.total) * 100) return ( -
-
- Storage - {percent}% used +
+
+
- -

- {formatFileSize(usage.used)} of {formatFileSize(usage.total)} +

+ {formatFileSize(usage.used)} of {formatFileSize(usage.total)} used

) diff --git a/src/components/nav-files.tsx b/src/components/nav-files.tsx index 8eabd3a..d618ff9 100755 --- a/src/components/nav-files.tsx +++ b/src/components/nav-files.tsx @@ -19,7 +19,6 @@ import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, - SidebarSeparator, } from "@/components/ui/sidebar" import { cn } from "@/lib/utils" @@ -84,8 +83,7 @@ export function NavFiles() { -
- +
diff --git a/src/components/nav-user.tsx b/src/components/nav-user.tsx index aac282e..3e0de3f 100755 --- a/src/components/nav-user.tsx +++ b/src/components/nav-user.tsx @@ -57,12 +57,12 @@ export function NavUser({ MV
- {user.name} - + {user.name} + {user.email}
- +