Skip to content

Commit 5171257

Browse files
adding responsive in the application
1 parent 8ee9814 commit 5171257

7 files changed

Lines changed: 228 additions & 19 deletions

File tree

components/docs/DocContent.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ export const DocContent: React.FC<DocContentProps> = memo(({
2929
<main
3030
className={cn(
3131
'flex-1 flex flex-col docs-compact',
32-
'px-8 py-8',
33-
'mr-64', // Account for fixed sidebar width (w-64 = 256px)
32+
'px-4 py-6 sm:px-6 sm:py-8 lg:px-8',
33+
'mr-0 lg:mr-64', // Account for fixed sidebar width on large screens only
3434
'min-h-[calc(100vh-4rem)]', // Ensure minimum height for sticky footer
3535
className
3636
)}

components/docs/DocTableOfContents.tsx

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export const DocTableOfContents: React.FC<DocTableOfContentsProps> = ({
4848
const nav = useNavigation();
4949
const router = useRouter();
5050
const [isActionsCollapsed, setIsActionsCollapsed] = useState(false);
51+
const [isMobileOpen, setIsMobileOpen] = useState(false);
5152
const prefetchedRef = useRef<Set<string>>(new Set());
5253
const scrollContainerRef = useRef<HTMLDivElement>(null);
5354
const hoverScrollRafRef = useRef<number | null>(null);
@@ -111,15 +112,8 @@ export const DocTableOfContents: React.FC<DocTableOfContentsProps> = ({
111112
};
112113
}, []);
113114

114-
return (
115-
<aside
116-
className={cn(
117-
'w-64 border-l border-gray-200 bg-gray-50',
118-
'fixed right-0 top-16 h-[calc(100vh-4rem)] flex flex-col',
119-
className
120-
)}
121-
>
122-
<div className="flex flex-col h-full">
115+
const sidebarContent = (
116+
<div className="flex flex-col h-full">
123117
{/* Scrollable section - "On This Page" and "Pages" */}
124118
<div ref={scrollContainerRef} className="p-6 pb-0 flex-1 overflow-y-auto no-scrollbar">
125119
{topLevelItems.length > 0 && (
@@ -320,7 +314,53 @@ export const DocTableOfContents: React.FC<DocTableOfContentsProps> = ({
320314
</div>
321315
</div>
322316
</div>
323-
</aside>
317+
);
318+
319+
return (
320+
<>
321+
<aside
322+
className={cn(
323+
'hidden lg:flex w-64 border-l border-gray-200 bg-gray-50',
324+
'fixed right-0 top-16 h-[calc(100vh-4rem)] flex-col',
325+
className
326+
)}
327+
>
328+
{sidebarContent}
329+
</aside>
330+
331+
<button
332+
type="button"
333+
onClick={() => setIsMobileOpen((prev) => !prev)}
334+
className="fixed right-4 bottom-4 z-30 rounded-full border border-gray-200 bg-white p-3 text-gray-700 shadow-md hover:bg-gray-50 lg:hidden"
335+
aria-label={isMobileOpen ? 'Close table of contents' : 'Open table of contents'}
336+
title={isMobileOpen ? 'Close table of contents' : 'Open table of contents'}
337+
>
338+
{isMobileOpen ? (
339+
<svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
340+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
341+
</svg>
342+
) : (
343+
<svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
344+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 6h11M9 12h11M9 18h11M5 6h.01M5 12h.01M5 18h.01" />
345+
</svg>
346+
)}
347+
</button>
348+
349+
{isMobileOpen && (
350+
<>
351+
<div
352+
className="fixed inset-0 z-30 bg-black/40 lg:hidden"
353+
onClick={() => setIsMobileOpen(false)}
354+
aria-hidden
355+
/>
356+
<aside
357+
className="fixed right-0 top-0 z-40 flex h-screen w-[82vw] max-w-[320px] flex-col border-l border-gray-200 bg-gray-50 shadow-xl lg:hidden"
358+
>
359+
{sidebarContent}
360+
</aside>
361+
</>
362+
)}
363+
</>
324364
);
325365
};
326366

components/docs/DocsLayoutClient.tsx

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ export function DocsLayoutClient({
2525
}: DocsLayoutClientProps) {
2626
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
2727
const [showExpandButton, setShowExpandButton] = useState(false);
28+
const [isMobileSidebarOpen, setIsMobileSidebarOpen] = useState(false);
29+
const hasSearchData = processedProjects.length > 0 || processedYourDocs.length > 0;
2830

2931
// CRITICAL: Memoize onToggleCollapse to prevent sidebar re-renders
3032
const handleToggleCollapse = useCallback(() => {
@@ -148,18 +150,35 @@ export function DocsLayoutClient({
148150
<div className="flex flex-1" style={{ fontFamily: 'var(--font-lilex), monospace' }}>
149151
<StableSidebar
150152
items={memoizedSidebarItems}
153+
className="hidden md:flex"
151154
isCollapsed={isSidebarCollapsed}
152155
onToggleCollapse={handleToggleCollapse}
153156
{...stableHandlers}
154157
/>
158+
{isMobileSidebarOpen && (
159+
<>
160+
<div
161+
className="fixed inset-0 z-30 bg-black/40 md:hidden"
162+
onClick={() => setIsMobileSidebarOpen(false)}
163+
aria-hidden
164+
/>
165+
<StableSidebar
166+
items={memoizedSidebarItems}
167+
className="!flex md:!hidden !w-[82vw] !max-w-[320px] !top-16 !h-[calc(100vh-4rem)] !z-40 shadow-xl"
168+
isCollapsed={false}
169+
onToggleCollapse={handleToggleCollapse}
170+
{...stableHandlers}
171+
/>
172+
</>
173+
)}
155174
{showExpandButton && isSidebarCollapsed && (
156175
<button
157176
type="button"
158177
onClick={() => {
159178
setShowExpandButton(false);
160179
setIsSidebarCollapsed(false);
161180
}}
162-
className="fixed left-0 p-1.5 bg-white border border-gray-200 border-l-0 rounded-r-md hover:bg-gray-50 text-gray-600 hover:text-gray-900 shadow-sm z-20 flex items-center justify-center transition-opacity duration-200"
181+
className="fixed left-0 p-1.5 bg-white border border-gray-200 border-l-0 rounded-r-md hover:bg-gray-50 text-gray-600 hover:text-gray-900 shadow-sm z-20 hidden md:flex items-center justify-center transition-opacity duration-200"
163182
aria-label="Expand sidebar"
164183
title="Expand sidebar"
165184
style={{
@@ -181,9 +200,42 @@ export function DocsLayoutClient({
181200
</svg>
182201
</button>
183202
)}
184-
<div className={`flex-1 min-h-screen bg-white transition-all duration-300 ${isSidebarCollapsed ? 'ml-0 pl-10' : 'ml-64'}`}>
203+
<div className={`flex-1 min-h-screen bg-white transition-all duration-300 ${isSidebarCollapsed ? 'ml-0 md:pl-10' : 'ml-0 md:ml-64'}`}>
185204
<DocsContentArea>{children}</DocsContentArea>
186205
</div>
206+
<button
207+
type="button"
208+
onClick={() => setIsMobileSidebarOpen((prev) => !prev)}
209+
className="fixed left-4 bottom-4 z-30 md:hidden rounded-full border border-gray-200 bg-white p-3 text-gray-700 shadow-md hover:bg-gray-50"
210+
aria-label={isMobileSidebarOpen ? 'Close left sidebar' : 'Open left sidebar'}
211+
title={isMobileSidebarOpen ? 'Close left sidebar' : 'Open left sidebar'}
212+
>
213+
{isMobileSidebarOpen ? (
214+
<svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
215+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
216+
</svg>
217+
) : (
218+
<svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
219+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 5h6v14H4zM13 7h7M13 12h7M13 17h7" />
220+
</svg>
221+
)}
222+
</button>
223+
{hasSearchData && (
224+
<button
225+
type="button"
226+
onClick={() => {
227+
window.dispatchEvent(new Event('open-docs-search'));
228+
}}
229+
className="fixed left-1/2 bottom-4 z-30 -translate-x-1/2 md:hidden inline-flex items-center gap-2 rounded-full border border-gray-200 bg-white px-4 py-2 text-sm text-gray-700 shadow-md hover:bg-gray-50"
230+
aria-label="Search documentation"
231+
title="Search documentation"
232+
>
233+
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
234+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-4.35-4.35M10.5 18a7.5 7.5 0 110-15 7.5 7.5 0 010 15z" />
235+
</svg>
236+
<span>Search docs</span>
237+
</button>
238+
)}
187239
</div>
188240
<CreateProjectModal />
189241
<CreateDocModal />

components/docs/DocsLoadingSkeleton.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function DocsLoadingSkeleton() {
99
return (
1010
<div className="flex flex-1 w-full min-h-[calc(100vh-4rem)]">
1111
<main
12-
className="flex-1 flex flex-col px-8 py-8 mr-64 min-h-[calc(100vh-4rem)]"
12+
className="flex-1 flex flex-col px-4 py-6 sm:px-6 sm:py-8 lg:px-8 mr-0 lg:mr-64 min-h-[calc(100vh-4rem)]"
1313
aria-hidden
1414
>
1515
<div className="w-full flex flex-col flex-1 min-h-0">
@@ -59,7 +59,7 @@ export function DocsLoadingSkeleton() {
5959
</div>
6060
</main>
6161
<aside
62-
className="w-64 border-l border-gray-200 bg-gray-50 fixed right-0 top-16 h-[calc(100vh-4rem)] flex flex-col flex-shrink-0"
62+
className="hidden lg:flex w-64 border-l border-gray-200 bg-gray-50 fixed right-0 top-16 h-[calc(100vh-4rem)] flex-col flex-shrink-0"
6363
aria-hidden
6464
>
6565
<div className="flex flex-col h-full">

components/docs/DocsPageContent.tsx

Lines changed: 105 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ const DocsPageContentComponent = ({
145145
const [publishModalOpen, setPublishModalOpen] = useState(false);
146146
const [publishDocumentId, setPublishDocumentId] = useState<string>('');
147147
const [publishDocumentName, setPublishDocumentName] = useState<string>('');
148+
const [isMobileProjectInfoOpen, setIsMobileProjectInfoOpen] = useState(false);
148149

149150
// Project members state
150151
interface ProjectMember {
@@ -310,14 +311,14 @@ const DocsPageContentComponent = ({
310311

311312
{/* Documents Grid */}
312313
<div className="mt-8">
313-
<div className="flex items-center justify-between mb-6">
314+
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 mb-6">
314315
<h2 className="text-2xl font-bold text-gray-900">Documents</h2>
315316
<button
316317
onClick={() => {
317318
// Get project ID from pageToRender (which is a ProcessedProject)
318319
handleCreateDoc(pageToRender.id, pageToRender.title);
319320
}}
320-
className="flex items-center gap-2 px-4 py-2 bg-[#CC561E] hover:bg-[#B84A17] text-white rounded-md transition-colors text-sm font-medium shadow-sm hover:shadow-md"
321+
className="w-full sm:w-auto inline-flex items-center justify-center gap-2 px-4 py-2 bg-[#CC561E] hover:bg-[#B84A17] text-white rounded-md transition-colors text-sm font-medium shadow-sm hover:shadow-md"
321322
aria-label="Create new document"
322323
title="Create new document"
323324
>
@@ -419,7 +420,7 @@ const DocsPageContentComponent = ({
419420
</div>
420421
</DocContent>
421422
{/* Right Sidebar for Project Overview */}
422-
<aside className="w-64 border-l border-gray-200 bg-gray-50 fixed right-0 top-16 h-[calc(100vh-4rem)] flex flex-col">
423+
<aside className="hidden lg:flex w-64 border-l border-gray-200 bg-gray-50 fixed right-0 top-16 h-[calc(100vh-4rem)] flex-col">
423424
<div className="p-6 flex-1 overflow-y-auto modern-scrollbar">
424425
<h2 className="text-sm font-semibold text-gray-900 mb-6">Project Info</h2>
425426
<div className="space-y-6">
@@ -493,6 +494,107 @@ const DocsPageContentComponent = ({
493494
</button>
494495
</div>
495496
</aside>
497+
<button
498+
type="button"
499+
onClick={() => setIsMobileProjectInfoOpen((prev) => !prev)}
500+
className="fixed right-4 bottom-4 z-30 rounded-full border border-gray-200 bg-white p-3 text-gray-700 shadow-md hover:bg-gray-50 lg:hidden"
501+
aria-label={isMobileProjectInfoOpen ? 'Close project info' : 'Open project info'}
502+
title={isMobileProjectInfoOpen ? 'Close project info' : 'Open project info'}
503+
>
504+
{isMobileProjectInfoOpen ? (
505+
<svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
506+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
507+
</svg>
508+
) : (
509+
<svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
510+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8h.01M11 12h1v4h1m-9-4a8 8 0 1116 0 8 8 0 01-16 0z" />
511+
</svg>
512+
)}
513+
</button>
514+
{isMobileProjectInfoOpen && (
515+
<>
516+
<div
517+
className="fixed inset-0 z-30 bg-black/40 lg:hidden"
518+
onClick={() => setIsMobileProjectInfoOpen(false)}
519+
aria-hidden
520+
/>
521+
<aside className="fixed right-0 top-0 z-40 flex h-screen w-[82vw] max-w-[320px] flex-col border-l border-gray-200 bg-gray-50 shadow-xl lg:hidden">
522+
<div className="p-6 flex-1 overflow-y-auto modern-scrollbar">
523+
<h2 className="text-sm font-semibold text-gray-900 mb-6">Project Info</h2>
524+
<div className="space-y-6">
525+
<div>
526+
<p className="text-xs text-gray-500 mb-2 uppercase tracking-wide font-medium">Members</p>
527+
{isLoadingMembers ? (
528+
<div className="text-xs text-gray-500">Loading...</div>
529+
) : projectMembers.length > 0 ? (
530+
<div className="space-y-2">
531+
{projectMembers.map((member) => (
532+
<div key={member.id} className="flex items-center gap-2">
533+
{member.imageUrl ? (
534+
<img
535+
src={member.imageUrl}
536+
alt={member.email}
537+
className="w-6 h-6 rounded-full flex-shrink-0"
538+
/>
539+
) : (
540+
<div className="w-6 h-6 rounded-full bg-gray-300 flex items-center justify-center flex-shrink-0">
541+
<span className="text-[10px] text-gray-600 font-medium">
542+
{member.email.charAt(0).toUpperCase()}
543+
</span>
544+
</div>
545+
)}
546+
<div className="flex-1 min-w-0">
547+
<p className="text-xs text-gray-700 truncate">{member.email}</p>
548+
<p className="text-[10px] text-gray-500 capitalize">{member.role}</p>
549+
</div>
550+
</div>
551+
))}
552+
</div>
553+
) : (
554+
<div className="text-xs text-gray-500">No members</div>
555+
)}
556+
</div>
557+
<div>
558+
<p className="text-xs text-gray-500 mb-2 uppercase tracking-wide font-medium">Documents</p>
559+
<p className="text-2xl font-bold text-gray-900">
560+
{pageToRender.documents?.length || 0}
561+
</p>
562+
</div>
563+
{pageToRender.lastUpdated && (
564+
<div>
565+
<p className="text-xs text-gray-500 mb-2 uppercase tracking-wide font-medium">Last Updated</p>
566+
<p className="text-sm text-gray-700">{pageToRender.lastUpdated}</p>
567+
</div>
568+
)}
569+
</div>
570+
</div>
571+
<div className="mt-auto p-6 pt-8 border-t border-gray-200 flex-shrink-0 bg-gray-50">
572+
<button
573+
onClick={() => {
574+
handleShareProject(pageToRender.id, pageToRender.title);
575+
setIsMobileProjectInfoOpen(false);
576+
}}
577+
className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-[#CC561E] hover:bg-[#B84A17] text-white rounded-md transition-colors text-sm font-medium shadow-sm hover:shadow-md"
578+
>
579+
<svg
580+
className="w-4 h-4"
581+
fill="none"
582+
stroke="currentColor"
583+
viewBox="0 0 24 24"
584+
>
585+
<path
586+
strokeLinecap="round"
587+
strokeLinejoin="round"
588+
strokeWidth={2}
589+
d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"
590+
/>
591+
</svg>
592+
Manage Access
593+
</button>
594+
</div>
595+
</aside>
596+
</>
597+
)}
496598
<CreateDocModal />
497599
<ShareModal
498600
isOpen={shareModalOpen}

components/docs/StableSidebar.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const deepCompareNavItems = (prev: NavItem[], next: NavItem[]): boolean => {
3131

3232
interface StableSidebarProps {
3333
items: NavItem[];
34+
className?: string;
3435
isCollapsed?: boolean;
3536
onToggleCollapse?: () => void;
3637
onCreateProject?: () => void;
@@ -47,6 +48,7 @@ export const StableSidebar = memo((props: StableSidebarProps) => {
4748
return (
4849
<DocSidebar
4950
items={props.items}
51+
className={props.className}
5052
isCollapsed={props.isCollapsed}
5153
onToggleCollapse={props.onToggleCollapse}
5254
onCreateProject={props.onCreateProject}

components/sections/Header.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@ export const Header: React.FC<HeaderProps> = ({
8787
};
8888
}, [projects.length, yourDocs.length]);
8989

90+
useEffect(() => {
91+
const handleOpenDocsSearch = () => {
92+
if (projects.length > 0 || yourDocs.length > 0) {
93+
setIsSearchOpen(true);
94+
}
95+
};
96+
97+
window.addEventListener('open-docs-search', handleOpenDocsSearch);
98+
return () => {
99+
window.removeEventListener('open-docs-search', handleOpenDocsSearch);
100+
};
101+
}, [projects.length, yourDocs.length]);
102+
90103
return (
91104
<header className="sticky top-0 z-50 w-full bg-background/80 backdrop-blur-md shadow-sm" style={{ fontFamily: 'var(--font-open-sans), sans-serif' }}>
92105
<div className="flex h-16 items-center justify-between">

0 commit comments

Comments
 (0)