Skip to content

Commit

Permalink
Merge pull request #7 from Ray-D-Song/dev
Browse files Browse the repository at this point in the history
feat: skeleton and mobile layout
  • Loading branch information
banzhe authored Oct 27, 2024
2 parents d7e5ba0 + b90f407 commit cbee29d
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 31 deletions.
38 changes: 38 additions & 0 deletions packages/shared/components/skelton-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { useState, useEffect } from 'react'

interface SkeletonWrapperProps {
loadingDeps: boolean
skeleton: React.ReactNode
children: React.ReactNode
minDisplayTime?: number
}

function SkeletonWrapper({
loadingDeps,
skeleton,
children,
minDisplayTime = 500
}: SkeletonWrapperProps) {
const [showSkeleton, setShowSkeleton] = useState(false)

useEffect(() => {
let timer: NodeJS.Timeout
if (loadingDeps) {
setShowSkeleton(true)
timer = setTimeout(() => {
if (!loadingDeps) {
setShowSkeleton(false)
}
}, minDisplayTime)
} else {
timer = setTimeout(() => {
setShowSkeleton(false)
}, minDisplayTime)
}
return () => clearTimeout(timer)
}, [loadingDeps, minDisplayTime])

return showSkeleton ? skeleton : children
}

export default SkeletonWrapper
16 changes: 16 additions & 0 deletions packages/web/src/components/hamburger.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { SquareMenu } from 'lucide-react'

interface HamburgerProps {
className?: string
onClick?: () => void
}

function Hamburger({ className, onClick }: HamburgerProps) {
return (
<div className={`text-white bg-blue-600 py-2 pr-3 pl-1 rounded-r-[50%] ${className}`} onClick={onClick}>
<SquareMenu className="h-5 w-5" />
</div>
)
}

export default Hamburger
2 changes: 1 addition & 1 deletion packages/web/src/components/list-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function ListView({ pages, children, imgPreview, onItemClick }: ListViewProps) {
<TableBody>
{pages?.map(page => (
<TableRow key={page.id} className="cursor-pointer z-10" onClick={() => handleClickPage(page)} onMouseEnter={e => handleHoverPage(e, page)} onMouseLeave={handleLeavePage}>
<TableCell>{page.title}</TableCell>
<TableCell className="line-clamp-3">{page.title}</TableCell>
<TableCell>{page.createdAt.toLocaleString()}</TableCell>
{children && (
<TableCell>
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/components/page-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function PageCard({ page, onPageDelete }: { page: Page, onPageDelete?: (page: Pa
className="cursor-pointer hover:shadow-lg transition-shadow flex flex-col relative group"
>
<CardHeader>
<CardTitle className="leading-8 text-lg">{page.title}</CardTitle>
<CardTitle className="leading-8 text-lg line-clamp-2">{page.title}</CardTitle>
</CardHeader>
<CardContent className="flex-1">
{
Expand Down
49 changes: 34 additions & 15 deletions packages/web/src/components/side-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import { Button } from '@web-archive/shared/components/button'
import { LogOut, Plus, Settings, Trash } from 'lucide-react'
import type { Folder as FolderType, Page } from '@web-archive/shared/types'
import Folder from '@web-archive/shared/components/folder'
import { Skeleton } from '@web-archive/shared/components/skeleton'
import { useRequest } from 'ahooks'
import { useEffect, useState } from 'react'
import toast from 'react-hot-toast'
import { isNil, isNumberString } from '@web-archive/shared/utils'
import { useLocation } from 'react-router-dom'
import SkeletonWrapper from '@web-archive/shared/components/skelton-wrapper'
import NewFolderDialog from './new-folder-dialog'
import EditFolderDialog from './edit-folder-dialog'
import SettingDialog from './setting-dialog'
import Hamburger from './hamburger'
import { useNavigate, useParams } from '~/router'
import emitter from '~/utils/emitter'
import { deleteFolder, getAllFolder } from '~/data/folder'
Expand All @@ -28,7 +31,7 @@ function getNextFolderId(folders: Array<FolderType>, index: number) {

function SideBar() {
const navigate = useNavigate()
const { data: folders, refresh, mutate: setFolders } = useRequest(getAllFolder)
const { data: folders, refresh, mutate: setFolders, loading: foldersLoading } = useRequest(getAllFolder)

const [openedFolder, setOpenedFolder] = useState<number | null>(null)
const handleFolderClick = (id: number) => {
Expand Down Expand Up @@ -98,8 +101,11 @@ function SideBar() {

const [settingDialogOpen, setSettingDialogOpen] = useState(false)

const [isSidebarOpen, setIsSidebarOpen] = useState(false)

return (
<div className="w-64 h-screen shadow-lg dark:shadow-zinc-600 dark:shadow-sm">
<div className={`w-64 h-screen shadow-lg bg-white dark:bg-[#020817] dark:shadow-zinc-600 dark:shadow-sm transition-all duration-300 fixed lg:relative lg:block lg:z-auto z-50 ${isSidebarOpen ? 'translate-x-0' : '-translate-x-full'}`}>
<Hamburger className="lg:hidden block absolute top-[50%] right-[-2.2rem] cursor-pointer" onClick={() => setIsSidebarOpen(prev => !prev)} />
<NewFolderDialog afterSubmit={refresh} open={newFolderDialogOpen} setOpen={setNewFolderDialogOpen} />
<EditFolderDialog
afterSubmit={refresh}
Expand All @@ -111,25 +117,38 @@ function SideBar() {
<div className="h-screen">
<div className="p-4 min-h-full flex flex-col">
<div className="flex space-x-2">
<Button className="flex-1 text-sm justify-center opacity-60 hover:opacity-100 transition-opacity duration-300" onClick={() => setNewFolderDialogOpen(true)}>
<Button className="flex-1 text-sm justify-center" onClick={() => setNewFolderDialogOpen(true)}>
<Plus className="w-5 h-5 mr-2" />
New Folder
</Button>
</div>
<ScrollArea className="h-[calc(100vh-210px)]">
<ul className="flex flex-col gap-2 justify-center items-center py-4">
{folders?.map(folder => (
<Folder
key={folder.id}
name={folder.name}
id={folder.id}
isOpen={openedFolder === folder.id}
onClick={handleFolderClick}
onDropPage={(page) => { handleDropPage(folder.id, page) }}
onDelete={handleDeleteFolder}
onEdit={handleEditFolder}
/>
))}
<SkeletonWrapper
loadingDeps={foldersLoading}
skeleton={(
<>
{Array.from({ length: 3 }).map((_, index) => (
<Skeleton key={index} className="w-full h-10" />
))}
</>
)}
>
{
folders?.map(folder => (
<Folder
key={folder.id}
name={folder.name}
id={folder.id}
isOpen={openedFolder === folder.id}
onClick={handleFolderClick}
onDropPage={(page) => { handleDropPage(folder.id, page) }}
onDelete={handleDeleteFolder}
onEdit={handleEditFolder}
/>
))
}
</SkeletonWrapper>
</ul>
</ScrollArea>
<div className="border-b border-gray-200 dark:border-gray-800 my-2" />
Expand Down
23 changes: 15 additions & 8 deletions packages/web/src/components/view-toggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@ import AppContext from '../store/app'
function ViewToggle() {
const { view, setView } = useContext(AppContext)
return (
<div className="flex">
<Button variant={view === 'card' ? 'default' : 'outline'} size="icon" className="rounded-br-none rounded-tr-none border-r-0" onClick={() => setView('card')}>
<Grid2X2 className="h-4 w-4" />
</Button>
<Button variant={view === 'list' ? 'default' : 'outline'} size="icon" className="rounded-bl-none rounded-tl-none border-l-0" onClick={() => setView('list')}>
<List className="h-4 w-4" />
</Button>
</div>
<>
<div className="flex hidden lg:block">
<Button variant={view === 'card' ? 'default' : 'outline'} size="icon" className="rounded-br-none rounded-tr-none border-r-0" onClick={() => setView('card')}>
<Grid2X2 className="h-4 w-4" />
</Button>
<Button variant={view === 'list' ? 'default' : 'outline'} size="icon" className="rounded-bl-none rounded-tl-none border-l-0" onClick={() => setView('list')}>
<List className="h-4 w-4" />
</Button>
</div>
<div className="lg:hidden block">
<Button variant="outline" size="icon" onClick={() => setView(view === 'card' ? 'list' : 'card')}>
{view === 'card' ? <List className="h-4 w-4" /> : <Grid2X2 className="h-4 w-4" />}
</Button>
</div>
</>
)
}

Expand Down
4 changes: 1 addition & 3 deletions packages/web/src/pages/(layout)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ function Layout() {
position="top-center"
reverseOrder={false}
/>
<div className="w-64">
<SideBar />
</div>
<SideBar />
<div className="flex-1 flex flex-col">
<Header keyword={keyword} setKeyword={setKeyword} handleSearch={handleSearch} />
<Outlet context={{ keyword, searchTrigger }} />
Expand Down
2 changes: 1 addition & 1 deletion packages/web/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default defineConfig({
port: 7749,
proxy: {
'/api': {
target: 'http://localhost:9981/',
target: 'https://web-archive-egm.pages.dev',
changeOrigin: true,
},
},
Expand Down
8 changes: 6 additions & 2 deletions roadmap.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
- [ ] Showcase feature (Show some of your collected web pages)
- [ ] Tag feature (Tag your web pages, and use tag as a filter condition)
- [x] Showcase feature (Show some of your collected web pages)
- [ ] Tag feature (Tag your web pages, and use tag as a filter condition)
- [x] Skeleton screen
- [ ] Update page meta information
- [x] Mobile support
- [ ] PWA support

0 comments on commit cbee29d

Please sign in to comment.