Skip to content

Commit

Permalink
0.0.3
Browse files Browse the repository at this point in the history
- Add component pomodoro timer
- Add component agenda sidebar
- Break Kanban board into smaller components
- restore tailwind config
- simplify the navbar first
  • Loading branch information
tanghoong committed Sep 13, 2024
1 parent 263ca24 commit bbbbcf0
Show file tree
Hide file tree
Showing 13 changed files with 757 additions and 141 deletions.
21 changes: 21 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
:root {
--background: #ffffff;
--foreground: #171717;
--scrollbar-thumb: #586e75;
--scrollbar-track: #073642;
}

@media (prefers-color-scheme: dark) {
Expand All @@ -18,10 +20,29 @@ body {
color: var(--foreground);
background: var(--background);
font-family: Arial, Helvetica, sans-serif;
transition: padding-right 0.3s ease-in-out;
}

@layer utilities {
.text-balance {
text-wrap: balance;
}
}

.custom-scrollbar {
scrollbar-width: thin;
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
}

.custom-scrollbar::-webkit-scrollbar {
width: 8px;
}

.custom-scrollbar::-webkit-scrollbar-track {
background: var(--scrollbar-track);
}

.custom-scrollbar::-webkit-scrollbar-thumb {
background-color: var(--scrollbar-thumb);
border-radius: 4px;
}
86 changes: 61 additions & 25 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
'use client'

import React, { useState, useCallback, useMemo } from 'react';
import React, { useState, useCallback, useMemo, useEffect } from 'react';
import { useBoards, useUpdateBoard, useDeleteBoard, useAddBoard, useReorderBoards } from '@/hooks/useData';
import { Board } from '@/types';
import dynamic from 'next/dynamic';
import NewBoardModal from '@/components/NewBoardModal';
import BoardList from '@/components/BoardList';
import TemplateList from '@/components/TemplateList';
import Accordion from '@/components/Accordion';
import { Plus, Search } from 'lucide-react';
import AgendaSidebar from '@/components/AgendaSidebar';
import { Plus, Search, Calendar, PanelRight } from 'lucide-react';
import { useRouter } from 'next/navigation';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import ResetDatabaseButton from '@/components/ResetDatabaseButton';

const boardTemplates = [
{
Expand Down Expand Up @@ -111,7 +114,7 @@ const boardTemplates = [
}
];

export default function Home() {
const HomeContent: React.FC = () => {
const router = useRouter();
const { data: boards, isLoading, error } = useBoards();
const updateBoard = useUpdateBoard();
Expand All @@ -124,6 +127,17 @@ export default function Home() {
const [searchTerm, setSearchTerm] = useState('');
const [activeTag, setActiveTag] = useState('all');
const [expandedSection, setExpandedSection] = useState<string | null>('pinned');
const [isAgendaOpen, setIsAgendaOpen] = useState(() => {
if (typeof window !== 'undefined') {
const saved = localStorage.getItem('isAgendaOpen');
return saved !== null ? JSON.parse(saved) : true;
}
return true;
});

useEffect(() => {
localStorage.setItem('isAgendaOpen', JSON.stringify(isAgendaOpen));
}, [isAgendaOpen]);

const handleEditBoard = useCallback((board: Board) => {
// Implement edit functionality
Expand Down Expand Up @@ -185,17 +199,26 @@ export default function Home() {
const tags = ['all', ...Array.from(new Set(boardTemplates.map(template => template.type)))];

return (
<DndProvider backend={HTML5Backend}>
<div className={`transition-all duration-300 ease-in-out ${isAgendaOpen ? 'mr-96' : ''}`}>
<div className="w-full max-w-6xl mx-auto px-4">
{/* Header */}
<div className="flex justify-between items-center mb-8">
<h1 className="text-3xl font-bold text-solarized-cyan">Welcome, Charlie</h1>
<button
onClick={() => setIsNewBoardModalOpen(true)}
className="bg-solarized-blue text-solarized-base3 px-4 py-2 rounded-full hover:bg-opacity-80 transition-colors flex items-center text-sm"
>
<Plus size={18} className="mr-2" /> New Board
</button>
<div className="flex items-center space-x-4">
<ResetDatabaseButton />
<button
onClick={() => setIsNewBoardModalOpen(true)}
className="bg-solarized-blue text-solarized-base3 hover:bg-opacity-80 transition-colors p-1 rounded-full"
>
<Plus size={16} />
</button>
<button
onClick={() => setIsAgendaOpen(!isAgendaOpen)}
className="text-solarized-base1 hover:text-solarized-base0 p-2 rounded-full hover:bg-solarized-base02"
>
<PanelRight size={24} />
</button>
</div>
</div>

{/* Board Lists */}
Expand All @@ -212,13 +235,12 @@ export default function Home() {
>
{pinnedBoards.length > 0 ? (
<BoardList
boards={pinnedBoards}
onMoveBoard={handleMoveBoard}
onEditBoard={handleEditBoard}
onViewBoard={handleViewBoard}
onDeleteBoard={handleDeleteBoard}
onPinBoard={handlePinBoard}
/>
boards={pinnedBoards}
onMoveBoard={handleMoveBoard}
onEditBoard={handleEditBoard}
onViewBoard={handleViewBoard}
onDeleteBoard={handleDeleteBoard}
onPinBoard={handlePinBoard} title={''} />
) : (
<p className="text-solarized-base1">No pinned boards yet. Pin a board to see it here!</p>
)}
Expand All @@ -230,13 +252,12 @@ export default function Home() {
>
{allBoards.length > 0 ? (
<BoardList
boards={allBoards}
onMoveBoard={handleMoveBoard}
onEditBoard={handleEditBoard}
onViewBoard={handleViewBoard}
onDeleteBoard={handleDeleteBoard}
onPinBoard={handlePinBoard}
/>
boards={allBoards}
onMoveBoard={handleMoveBoard}
onEditBoard={handleEditBoard}
onViewBoard={handleViewBoard}
onDeleteBoard={handleDeleteBoard}
onPinBoard={handlePinBoard} title={''} />
) : (
<p className="text-solarized-base1">No boards yet. Create a new board to get started!</p>
)}
Expand Down Expand Up @@ -313,7 +334,22 @@ export default function Home() {
</div>
</div>
)}

<AgendaSidebar isOpen={isAgendaOpen} onClose={() => setIsAgendaOpen(false)} />
</div>
</DndProvider>
</div>
);
};

const DndProviderWithNoSSR = dynamic(
() => import('react-dnd').then((mod) => mod.DndProvider),
{ ssr: false }
);

export default function Home() {
return (
<DndProviderWithNoSSR backend={HTML5Backend}>
<HomeContent />
</DndProviderWithNoSSR>
);
}
94 changes: 94 additions & 0 deletions src/components/AgendaSidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from 'react';
import { X, Calendar, Clock, CheckSquare } from 'lucide-react';

interface AgendaSidebarProps {
isOpen: boolean;
onClose: () => void;
}

const AgendaSidebar: React.FC<AgendaSidebarProps> = ({ isOpen, onClose }) => {
if (!isOpen) return null;

return (
<div className="fixed inset-y-0 mt-16 right-0 w-96 bg-solarized-base02 shadow-lg z-10 transform transition-all duration-300 ease-in-out">
<div className="flex flex-col h-full p-4">
<div className="flex justify-between items-center mb-6">
<h2 className="text-xl font-bold text-solarized-base1">Agenda</h2>
<button
onClick={onClose}
className="text-solarized-base1 hover:text-solarized-base0 transition-colors"
>
<X size={20} />
</button>
</div>

<div className="space-y-6 overflow-y-auto flex-grow">
<AgendaSection
title="Today's Schedule"
icon={<Calendar size={16} />}
color="text-solarized-blue"
items={[
{ time: '9:00 AM', description: 'Team Meeting' },
{ time: '11:00 AM', description: 'Client Call' },
{ time: '2:00 PM', description: 'Project Review' },
]}
/>

<AgendaSection
title="Upcoming Deadlines"
icon={<Clock size={16} />}
color="text-solarized-cyan"
items={[
{ time: '2 days', description: 'Project A' },
{ time: 'Tomorrow', description: 'Task B' },
{ time: 'Next week', description: 'Presentation' },
]}
/>

<AgendaSection
title="Quick Tasks"
icon={<CheckSquare size={16} />}
color="text-solarized-green"
items={[
{ description: 'Send follow-up email' },
{ description: 'Prepare meeting notes' },
{ description: 'Update project timeline' },
]}
isCheckList
/>
</div>
</div>
</div>
);
};

interface AgendaSectionProps {
title: string;
icon: React.ReactNode;
color: string;
items: Array<{ time?: string; description: string }>;
isCheckList?: boolean;
}

const AgendaSection: React.FC<AgendaSectionProps> = ({ title, icon, color, items, isCheckList }) => (
<section>
<h3 className={`text-sm font-semibold ${color} mb-2 flex items-center`}>
{icon}
<span className="ml-2">{title}</span>
</h3>
<ul className="space-y-1 text-sm text-solarized-base1">
{items.map((item, index) => (
<li key={index} className="flex items-center">
{isCheckList ? (
<input type="checkbox" className="mr-2 form-checkbox h-3 w-3 text-solarized-blue rounded" />
) : (
<span className="w-16 text-xs text-solarized-base0">{item.time}</span>
)}
<span className="truncate">{item.description}</span>
</li>
))}
</ul>
</section>
);

export default AgendaSidebar;
5 changes: 4 additions & 1 deletion src/components/BoardItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ const BoardItem: React.FC<BoardItemProps> = ({ board, index, onMove, onEdit, onV

return (
<div
ref={(node) => drag(drop(node))}
ref={node => {
drag(node);
drop(node);
}}
className={`bg-solarized-base02 p-4 rounded-lg transition-colors ${
isDragging ? 'opacity-50 shadow-lg outline outline-2 outline-solarized-blue' : 'hover:bg-solarized-base01'
}`}
Expand Down
22 changes: 6 additions & 16 deletions src/components/KanbanBoard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Plus, Edit2, Trash2, GripVertical } from 'lucide-react';
import { toast } from 'react-hot-toast';
import CardModal from './CardModal';
import CardDetailModal from './CardDetailModal';
import AddListForm from './KanbanBoard/AddListForm';

interface KanbanBoardProps {
boardId: string;
Expand Down Expand Up @@ -223,6 +224,11 @@ const KanbanBoard: React.FC<KanbanBoardProps> = ({ boardId }) => {
return (
<DndProvider backend={HTML5Backend}>
<div className="flex overflow-x-auto p-2 space-x-2 custom-scrollbar min-h-[calc(100vh-8rem)] max-h-[calc(100vh-8rem)] snap-x snap-mandatory">
<AddListForm
onAddList={handleAddList}
totalLists={orderedLists.length}
totalTasks={tasks?.length || 0}
/>
{orderedLists.map((list, index) => (
<ListComponent
key={list.id}
Expand All @@ -244,22 +250,6 @@ const KanbanBoard: React.FC<KanbanBoardProps> = ({ boardId }) => {
setSelectedCard={setSelectedCard}
/>
))}
<div className="w-72 flex-shrink-0 snap-center p-2">
<input
type="text"
value={newListTitle}
onChange={(e) => setNewListTitle(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleAddList()}
placeholder="Enter list title"
className="bg-solarized-base01 text-solarized-base3 px-2 py-1 rounded w-full mb-2 text-sm"
/>
<button
onClick={handleAddList}
className="bg-solarized-blue text-solarized-base3 px-2 py-1 rounded w-full text-sm hover:bg-opacity-80 transition-colors flex items-center justify-center"
>
<Plus size={14} className="mr-1" /> Add List
</button>
</div>
</div>
{selectedCard && (
<CardDetailModal
Expand Down
Loading

0 comments on commit bbbbcf0

Please sign in to comment.