diff --git a/packages/web/index.html b/packages/web/index.html index 01f6a8d2..54bca434 100644 --- a/packages/web/index.html +++ b/packages/web/index.html @@ -5,7 +5,7 @@ - + GraphDone - Project Management Reimagined diff --git a/packages/web/src/components/CardView.tsx b/packages/web/src/components/CardView.tsx index 4e44c174..291f2260 100644 --- a/packages/web/src/components/CardView.tsx +++ b/packages/web/src/components/CardView.tsx @@ -109,7 +109,7 @@ const getContributorAvatar = (contributor?: string) => { const CardView: React.FC = ({ filteredNodes, handleEditNode, edges }) => { return ( -
+
{[...filteredNodes] .sort((a, b) => { const dateA = new Date(a.updatedAt || a.createdAt).getTime(); diff --git a/packages/web/src/components/Layout.tsx b/packages/web/src/components/Layout.tsx index 76757289..03dc498e 100644 --- a/packages/web/src/components/Layout.tsx +++ b/packages/web/src/components/Layout.tsx @@ -32,7 +32,7 @@ export function Layout({ children }: LayoutProps) { return (
{/* Mobile menu button */} -
+
- {/* Right Sidebar - Overlay */} + {/* Right Sidebar - Overlay (desktop only) */} {showProjectHealth && ( -
+
)} diff --git a/packages/web/src/index.css b/packages/web/src/index.css index 3a78a08e..8f668025 100644 --- a/packages/web/src/index.css +++ b/packages/web/src/index.css @@ -688,6 +688,27 @@ input[type="date"]:focus { input, textarea, [contenteditable], .select-text { user-select: text !important; } + + /* Hide the scrollbar on horizontally-scrollable strips (mobile view tabs etc.) + while keeping them swipe-scrollable. */ + .no-scrollbar { + -ms-overflow-style: none; + scrollbar-width: none; + } + .no-scrollbar::-webkit-scrollbar { + display: none; + } + + /* Dynamic viewport height: fills the visible area on mobile browsers, accounting + for the collapsing address bar (falls back to vh where dvh is unsupported). */ + .h-dvh-screen { + height: 100vh; + height: 100dvh; + } + + /* Safe-area insets for notched devices (requires viewport-fit=cover). */ + .pt-safe { padding-top: env(safe-area-inset-top); } + .pb-safe { padding-bottom: env(safe-area-inset-bottom); } } @keyframes fadeIn { diff --git a/packages/web/src/pages/Signin.tsx b/packages/web/src/pages/Signin.tsx index b3c2cdb9..b40708d5 100644 --- a/packages/web/src/pages/Signin.tsx +++ b/packages/web/src/pages/Signin.tsx @@ -426,16 +426,20 @@ export function Signin() { {/* Header */}
- GraphDone Logo - GraphDone + GraphDone Logo + GraphDone

Welcome Back

Enter your credentials to join the team

{/* Login Form */} -
- {/* Social Login Buttons */} + + {/* Social Login Buttons — only when at least one provider is actually + configured; otherwise the whole block (and its divider) is hidden so + no setup hints leak to end users (cloud uses email + guest). */} + {(oauthConfig?.google?.configured || oauthConfig?.linkedin?.configured || oauthConfig?.github?.configured) && ( + <>
@@ -482,7 +486,7 @@ export function Signin() { ? 'text-teal-400 bg-gray-900/95 border border-teal-500/30' : 'text-gray-300 bg-gray-900/95 border border-gray-700/50' }`}> - {oauthConfig?.linkedin.configured ? 'Sign in with LinkedIn' : 'Run: ./scripts/setup-oauth.sh'} + {oauthConfig?.linkedin.configured ? 'Sign in with LinkedIn' : 'Not configured'} @@ -503,7 +507,7 @@ export function Signin() { ? 'text-teal-400 bg-gray-900/95 border border-teal-500/30' : 'text-gray-300 bg-gray-900/95 border border-gray-700/50' }`}> - {oauthConfig?.github.configured ? 'Sign in with GitHub' : 'Run: ./scripts/setup-oauth.sh'} + {oauthConfig?.github.configured ? 'Sign in with GitHub' : 'Not configured'}
@@ -516,6 +520,8 @@ export function Signin() { Or sign in with your credentials
+ + )} {/* Sign In Method Toggle */}
diff --git a/packages/web/src/pages/Signup.tsx b/packages/web/src/pages/Signup.tsx index 0fcaaa04..3414472e 100644 --- a/packages/web/src/pages/Signup.tsx +++ b/packages/web/src/pages/Signup.tsx @@ -295,8 +295,8 @@ export function Signup() { {/* Header */}
- GraphDone Logo - GraphDone + GraphDone Logo + GraphDone

Create Your Account

Join the decentralized project management revolution

@@ -364,8 +364,11 @@ export function Signup() {
) : ( - - {/* Social Signup Buttons */} + + {/* Social Signup Buttons — only when at least one provider is configured; + otherwise the whole block (and divider) is hidden so no setup hints leak. */} + {(oauthConfig?.google?.configured || oauthConfig?.linkedin?.configured || oauthConfig?.github?.configured) && ( + <>
@@ -412,7 +415,7 @@ export function Signup() { ? 'text-teal-400 bg-gray-900/95 border border-teal-500/30' : 'text-gray-300 bg-gray-900/95 border border-gray-700/50' }`}> - {oauthConfig?.linkedin.configured ? 'Sign up with LinkedIn' : 'Run: ./scripts/setup-oauth.sh'} + {oauthConfig?.linkedin.configured ? 'Sign up with LinkedIn' : 'Not configured'} @@ -433,7 +436,7 @@ export function Signup() { ? 'text-teal-400 bg-gray-900/95 border border-teal-500/30' : 'text-gray-300 bg-gray-900/95 border border-gray-700/50' }`}> - {oauthConfig?.github.configured ? 'Sign up with GitHub' : 'Run: ./scripts/setup-oauth.sh'} + {oauthConfig?.github.configured ? 'Sign up with GitHub' : 'Not configured'}
@@ -446,6 +449,8 @@ export function Signup() { Or sign up with your credentials
+ + )} {/* Name Field */}
diff --git a/packages/web/src/pages/Workspace.tsx b/packages/web/src/pages/Workspace.tsx index e9826c85..dcf463db 100644 --- a/packages/web/src/pages/Workspace.tsx +++ b/packages/web/src/pages/Workspace.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { Plus, Share2, Users, Table, Activity, Network, CreditCard, Columns, CalendarDays, GanttChartSquare, LayoutDashboard, Database, AlertTriangle, Map, X, Minimize2, Edit3, Trash2, FolderPlus, ChevronLeft, ChevronRight } from 'lucide-react'; import { createPortal } from 'react-dom'; import { useQuery } from '@apollo/client'; @@ -25,7 +25,16 @@ export function Workspace() { const [showDeleteGraphModal, setShowDeleteGraphModal] = useState(false); const [showGraphSelectionModal, setShowGraphSelectionModal] = useState(false); const [graphToEdit, setGraphToEdit] = useState(null); - const [viewMode, setViewMode] = useState<'graph' | 'dashboard' | 'table' | 'cards' | 'kanban' | 'gantt' | 'calendar' | 'activity'>('graph'); + const [viewMode, setViewMode] = useState<'graph' | 'dashboard' | 'table' | 'cards' | 'kanban' | 'gantt' | 'calendar' | 'activity'>(() => { + if (typeof window === 'undefined') return 'graph'; + const saved = window.localStorage.getItem('graphdone:viewMode'); + if (saved) return saved as any; + // On the go: a phone-sized screen lands on the readable card list, not the graph. + return window.matchMedia('(max-width: 767px)').matches ? 'cards' : 'graph'; + }); + const [isMobile, setIsMobile] = useState(() => + typeof window !== 'undefined' && window.matchMedia('(max-width: 767px)').matches + ); const [showMiniMap, setShowMiniMap] = useState(true); const { currentGraph, availableGraphs, getBreadcrumb, ascendTo } = useGraph(); const breadcrumb = getBreadcrumb(); @@ -33,6 +42,17 @@ export function Workspace() { const { currentTeam, currentUser } = useAuth(); const { health, loading: healthLoading, error: healthError } = useHealthStatus(); + useEffect(() => { + try { window.localStorage.setItem('graphdone:viewMode', viewMode); } catch { /* private mode */ } + }, [viewMode]); + + useEffect(() => { + const mq = window.matchMedia('(max-width: 767px)'); + const handler = (e: MediaQueryListEvent) => setIsMobile(e.matches); + mq.addEventListener('change', handler); + return () => mq.removeEventListener('change', handler); + }, []); + // Get real-time counts for header display const { data: workItemsData } = useQuery(GET_WORK_ITEMS, { variables: currentGraph ? { @@ -66,9 +86,9 @@ export function Workspace() { return (
{/* Header with Graph Context */} -
+
{/* Responsive Layout Container */} -
+
{/* Left Section: Graph Selector */}
@@ -103,118 +123,119 @@ export function Workspace() {
- {/* Center Section: View Mode Buttons (Always Centered) */} -
-
+ {/* Center Section: View Mode Buttons — horizontally scrollable on mobile so + all eight stay reachable without clipping on a phone-width screen. */} +
+