diff --git a/apps/drive-web/src/components/ui/middle-truncated-text.tsx b/apps/drive-web/src/components/ui/middle-truncated-text.tsx
new file mode 100644
index 0000000..240dcf6
--- /dev/null
+++ b/apps/drive-web/src/components/ui/middle-truncated-text.tsx
@@ -0,0 +1,13 @@
+function MiddleTruncatedText({ children }: { children: string }) {
+ const LAST_PART_LENGTH = 3
+ const lastPart = children.slice(children.length - LAST_PART_LENGTH)
+ const firstPart = children.slice(0, children.length - LAST_PART_LENGTH)
+ return (
+
+ {firstPart}
+ {lastPart}
+
+ )
+}
+
+export { MiddleTruncatedText }
diff --git a/apps/drive-web/src/dashboard/dashboard-sidebar.tsx b/apps/drive-web/src/dashboard/dashboard-sidebar.tsx
index 351310b..0a86991 100644
--- a/apps/drive-web/src/dashboard/dashboard-sidebar.tsx
+++ b/apps/drive-web/src/dashboard/dashboard-sidebar.tsx
@@ -3,8 +3,8 @@ import { Link, useLocation } from "@tanstack/react-router"
import { useQuery as useConvexQuery } from "convex/react"
import { useAtomValue } from "jotai"
import {
+ ClockIcon,
FilesIcon,
- HomeIcon,
LogOutIcon,
SettingsIcon,
TrashIcon,
@@ -66,10 +66,10 @@ function MainSidebarMenu() {
return (
-
-
-
- Home
+
+
+
+ Recent
diff --git a/apps/drive-web/src/files/file-grid.tsx b/apps/drive-web/src/files/file-grid.tsx
new file mode 100644
index 0000000..13a9666
--- /dev/null
+++ b/apps/drive-web/src/files/file-grid.tsx
@@ -0,0 +1,19 @@
+import type { Doc } from "@fileone/convex/dataModel"
+import { TextFileIcon } from "../components/icons/text-file-icon"
+import { MiddleTruncatedText } from "../components/ui/middle-truncated-text"
+
+export function FileGrid({ files }: { files: Doc<"files">[] }) {
+ return (
+
+ {files.map((file) => (
+
+
+ {file.name}
+
+ ))}
+
+ )
+}
diff --git a/apps/drive-web/src/routeTree.gen.ts b/apps/drive-web/src/routeTree.gen.ts
index 2664b6c..6e2075f 100644
--- a/apps/drive-web/src/routeTree.gen.ts
+++ b/apps/drive-web/src/routeTree.gen.ts
@@ -15,6 +15,7 @@ import { Route as AuthenticatedRouteImport } from './routes/_authenticated'
import { Route as AuthenticatedIndexRouteImport } from './routes/_authenticated/index'
import { Route as LoginCallbackRouteImport } from './routes/login_.callback'
import { Route as AuthenticatedSidebarLayoutRouteImport } from './routes/_authenticated/_sidebar-layout'
+import { Route as AuthenticatedSidebarLayoutRecentRouteImport } from './routes/_authenticated/_sidebar-layout/recent'
import { Route as AuthenticatedSidebarLayoutHomeRouteImport } from './routes/_authenticated/_sidebar-layout/home'
import { Route as AuthenticatedSidebarLayoutDirectoriesDirectoryIdRouteImport } from './routes/_authenticated/_sidebar-layout/directories.$directoryId'
import { Route as AuthenticatedSidebarLayoutTrashDirectoriesDirectoryIdRouteImport } from './routes/_authenticated/_sidebar-layout/trash.directories.$directoryId'
@@ -48,6 +49,12 @@ const AuthenticatedSidebarLayoutRoute =
id: '/_sidebar-layout',
getParentRoute: () => AuthenticatedRoute,
} as any)
+const AuthenticatedSidebarLayoutRecentRoute =
+ AuthenticatedSidebarLayoutRecentRouteImport.update({
+ id: '/recent',
+ path: '/recent',
+ getParentRoute: () => AuthenticatedSidebarLayoutRoute,
+ } as any)
const AuthenticatedSidebarLayoutHomeRoute =
AuthenticatedSidebarLayoutHomeRouteImport.update({
id: '/home',
@@ -73,6 +80,7 @@ export interface FileRoutesByFullPath {
'/login/callback': typeof LoginCallbackRoute
'/': typeof AuthenticatedIndexRoute
'/home': typeof AuthenticatedSidebarLayoutHomeRoute
+ '/recent': typeof AuthenticatedSidebarLayoutRecentRoute
'/directories/$directoryId': typeof AuthenticatedSidebarLayoutDirectoriesDirectoryIdRoute
'/trash/directories/$directoryId': typeof AuthenticatedSidebarLayoutTrashDirectoriesDirectoryIdRoute
}
@@ -82,6 +90,7 @@ export interface FileRoutesByTo {
'/login/callback': typeof LoginCallbackRoute
'/': typeof AuthenticatedIndexRoute
'/home': typeof AuthenticatedSidebarLayoutHomeRoute
+ '/recent': typeof AuthenticatedSidebarLayoutRecentRoute
'/directories/$directoryId': typeof AuthenticatedSidebarLayoutDirectoriesDirectoryIdRoute
'/trash/directories/$directoryId': typeof AuthenticatedSidebarLayoutTrashDirectoriesDirectoryIdRoute
}
@@ -94,6 +103,7 @@ export interface FileRoutesById {
'/login_/callback': typeof LoginCallbackRoute
'/_authenticated/': typeof AuthenticatedIndexRoute
'/_authenticated/_sidebar-layout/home': typeof AuthenticatedSidebarLayoutHomeRoute
+ '/_authenticated/_sidebar-layout/recent': typeof AuthenticatedSidebarLayoutRecentRoute
'/_authenticated/_sidebar-layout/directories/$directoryId': typeof AuthenticatedSidebarLayoutDirectoriesDirectoryIdRoute
'/_authenticated/_sidebar-layout/trash/directories/$directoryId': typeof AuthenticatedSidebarLayoutTrashDirectoriesDirectoryIdRoute
}
@@ -105,6 +115,7 @@ export interface FileRouteTypes {
| '/login/callback'
| '/'
| '/home'
+ | '/recent'
| '/directories/$directoryId'
| '/trash/directories/$directoryId'
fileRoutesByTo: FileRoutesByTo
@@ -114,6 +125,7 @@ export interface FileRouteTypes {
| '/login/callback'
| '/'
| '/home'
+ | '/recent'
| '/directories/$directoryId'
| '/trash/directories/$directoryId'
id:
@@ -125,6 +137,7 @@ export interface FileRouteTypes {
| '/login_/callback'
| '/_authenticated/'
| '/_authenticated/_sidebar-layout/home'
+ | '/_authenticated/_sidebar-layout/recent'
| '/_authenticated/_sidebar-layout/directories/$directoryId'
| '/_authenticated/_sidebar-layout/trash/directories/$directoryId'
fileRoutesById: FileRoutesById
@@ -180,6 +193,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof AuthenticatedSidebarLayoutRouteImport
parentRoute: typeof AuthenticatedRoute
}
+ '/_authenticated/_sidebar-layout/recent': {
+ id: '/_authenticated/_sidebar-layout/recent'
+ path: '/recent'
+ fullPath: '/recent'
+ preLoaderRoute: typeof AuthenticatedSidebarLayoutRecentRouteImport
+ parentRoute: typeof AuthenticatedSidebarLayoutRoute
+ }
'/_authenticated/_sidebar-layout/home': {
id: '/_authenticated/_sidebar-layout/home'
path: '/home'
@@ -206,6 +226,7 @@ declare module '@tanstack/react-router' {
interface AuthenticatedSidebarLayoutRouteChildren {
AuthenticatedSidebarLayoutHomeRoute: typeof AuthenticatedSidebarLayoutHomeRoute
+ AuthenticatedSidebarLayoutRecentRoute: typeof AuthenticatedSidebarLayoutRecentRoute
AuthenticatedSidebarLayoutDirectoriesDirectoryIdRoute: typeof AuthenticatedSidebarLayoutDirectoriesDirectoryIdRoute
AuthenticatedSidebarLayoutTrashDirectoriesDirectoryIdRoute: typeof AuthenticatedSidebarLayoutTrashDirectoriesDirectoryIdRoute
}
@@ -213,6 +234,8 @@ interface AuthenticatedSidebarLayoutRouteChildren {
const AuthenticatedSidebarLayoutRouteChildren: AuthenticatedSidebarLayoutRouteChildren =
{
AuthenticatedSidebarLayoutHomeRoute: AuthenticatedSidebarLayoutHomeRoute,
+ AuthenticatedSidebarLayoutRecentRoute:
+ AuthenticatedSidebarLayoutRecentRoute,
AuthenticatedSidebarLayoutDirectoriesDirectoryIdRoute:
AuthenticatedSidebarLayoutDirectoriesDirectoryIdRoute,
AuthenticatedSidebarLayoutTrashDirectoriesDirectoryIdRoute:
diff --git a/apps/drive-web/src/routes/_authenticated/_sidebar-layout/recent.tsx b/apps/drive-web/src/routes/_authenticated/_sidebar-layout/recent.tsx
new file mode 100644
index 0000000..012ab84
--- /dev/null
+++ b/apps/drive-web/src/routes/_authenticated/_sidebar-layout/recent.tsx
@@ -0,0 +1,22 @@
+import { api } from "@fileone/convex/api"
+import { createFileRoute } from "@tanstack/react-router"
+import { useQuery as useConvexQuery } from "convex/react"
+import { FileGrid } from "@/files/file-grid"
+
+export const Route = createFileRoute("/_authenticated/_sidebar-layout/recent")({
+ component: RouteComponent,
+})
+
+function RouteComponent() {
+ const recentFiles = useConvexQuery(api.filesystem.fetchRecentFiles, {
+ limit: 100,
+ })
+
+ console.log("recentFiles", recentFiles)
+
+ return (
+
+
+
+ )
+}
diff --git a/apps/drive-web/src/routes/_authenticated/index.tsx b/apps/drive-web/src/routes/_authenticated/index.tsx
index 96d34c6..47994f6 100644
--- a/apps/drive-web/src/routes/_authenticated/index.tsx
+++ b/apps/drive-web/src/routes/_authenticated/index.tsx
@@ -5,5 +5,5 @@ export const Route = createFileRoute("/_authenticated/")({
})
function RouteComponent() {
- return
+ return
}
diff --git a/packages/convex/filesystem.ts b/packages/convex/filesystem.ts
index 9420b04..d0db1f0 100644
--- a/packages/convex/filesystem.ts
+++ b/packages/convex/filesystem.ts
@@ -188,3 +188,12 @@ export const openFile = authenticatedMutation({
return await FileSystem.openFile(ctx, { fileId })
},
})
+
+export const fetchRecentFiles = authenticatedQuery({
+ args: {
+ limit: v.number(),
+ },
+ handler: async (ctx, { limit }) => {
+ return await FileSystem.fetchRecentFiles(ctx, { limit })
+ },
+})
diff --git a/packages/convex/model/filesystem.ts b/packages/convex/model/filesystem.ts
index dfddfd5..81fd1cf 100644
--- a/packages/convex/model/filesystem.ts
+++ b/packages/convex/model/filesystem.ts
@@ -265,3 +265,19 @@ export async function openFile(
shareToken: newFileShare.shareToken,
}
}
+
+export async function fetchRecentFiles(
+ ctx: AuthenticatedQueryCtx,
+ { limit }: { limit: number },
+) {
+ return await ctx.db
+ .query("files")
+ .withIndex("byLastAccessedAt", (q) =>
+ q
+ .eq("userId", ctx.user._id)
+ .eq("deletedAt", undefined)
+ .gte("lastAccessedAt", 0),
+ )
+ .order("desc")
+ .take(limit)
+}
diff --git a/packages/convex/schema.ts b/packages/convex/schema.ts
index a626c2f..237733b 100644
--- a/packages/convex/schema.ts
+++ b/packages/convex/schema.ts
@@ -17,7 +17,7 @@ const schema = defineSchema({
.index("byDirectoryId", ["userId", "directoryId", "deletedAt"])
.index("byUserId", ["userId", "deletedAt"])
.index("byDeletedAt", ["deletedAt"])
- .index("byLastAccessedAt", ["userId", "lastAccessedAt"])
+ .index("byLastAccessedAt", ["userId", "deletedAt", "lastAccessedAt"])
.index("uniqueFileInDirectory", [
"userId",
"directoryId",