diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-07-19 16:15:26 +0000 |
|---|---|---|
| committer | Mohamed Bassem <me@mbassem.com> | 2025-07-19 16:15:26 +0000 |
| commit | 61a6ac8323ed5e80af1dd4a0781796a140715b65 (patch) | |
| tree | c939dc1c4c1bce8cc1cb43977aab7773a1bc3b11 /apps | |
| parent | 2cce45b7ed04b819bf25fa8ac129f300e1469846 (diff) | |
| download | karakeep-61a6ac8323ed5e80af1dd4a0781796a140715b65.tar.zst | |
feat(web): Slightly nicer looking tags page
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/web/app/dashboard/tags/page.tsx | 12 | ||||
| -rw-r--r-- | apps/web/components/dashboard/tags/AllTagsView.tsx | 157 | ||||
| -rw-r--r-- | apps/web/components/dashboard/tags/BulkTagAction.tsx | 5 |
3 files changed, 94 insertions, 80 deletions
diff --git a/apps/web/app/dashboard/tags/page.tsx b/apps/web/app/dashboard/tags/page.tsx index 9108d6ba..f8e4d8ea 100644 --- a/apps/web/app/dashboard/tags/page.tsx +++ b/apps/web/app/dashboard/tags/page.tsx @@ -1,18 +1,8 @@ import AllTagsView from "@/components/dashboard/tags/AllTagsView"; -import { Separator } from "@/components/ui/separator"; -import { useTranslation } from "@/lib/i18n/server"; import { api } from "@/server/api/client"; export default async function TagsPage() { - // oxlint-disable-next-line rules-of-hooks - const { t } = await useTranslation(); const allTags = (await api.tags.list()).tags; - return ( - <div className="space-y-4 rounded-md border bg-background p-4"> - <span className="text-2xl">{t("tags.all_tags")}</span> - <Separator /> - <AllTagsView initialData={allTags} /> - </div> - ); + return <AllTagsView initialData={allTags} />; } diff --git a/apps/web/components/dashboard/tags/AllTagsView.tsx b/apps/web/components/dashboard/tags/AllTagsView.tsx index a1af5a56..965afa73 100644 --- a/apps/web/components/dashboard/tags/AllTagsView.tsx +++ b/apps/web/components/dashboard/tags/AllTagsView.tsx @@ -3,20 +3,27 @@ import React, { useEffect } from "react"; import { ActionButton } from "@/components/ui/action-button"; import ActionConfirmingDialog from "@/components/ui/action-confirming-dialog"; +import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible"; import InfoTooltip from "@/components/ui/info-tooltip"; -import { Separator } from "@/components/ui/separator"; import { Toggle } from "@/components/ui/toggle"; import { toast } from "@/components/ui/use-toast"; import useBulkTagActionsStore from "@/lib/bulkTagActions"; import { useTranslation } from "@/lib/i18n/client"; import { api } from "@/lib/trpc"; -import { ArrowDownAZ, Combine } from "lucide-react"; +import { ArrowDownAZ, Combine, Tag } from "lucide-react"; import type { ZGetTagResponse, ZTagBasic } from "@karakeep/shared/types/tags"; import { useDeleteUnusedTags } from "@karakeep/shared-react/hooks/tags"; @@ -151,12 +158,17 @@ export default function AllTagsView({ </div> ); } else { - tagPill = "No Tags"; + tagPill = ( + <div className="py-8 text-center"> + <Tag className="mx-auto mb-4 h-12 w-12 text-gray-300" /> + <p className="mb-4 text-gray-500">No custom tags yet</p> + </div> + ); } return tagPill; }; return ( - <> + <div className="flex flex-col gap-4"> {selectedTag && ( <DeleteTagConfirmationDialog tag={selectedTag} @@ -169,69 +181,80 @@ export default function AllTagsView({ }} /> )} - <div className="flex justify-end gap-x-2"> - <BulkTagAction /> - <Toggle - variant="outline" - aria-label="Toggle bold" - pressed={draggingEnabled} - onPressedChange={toggleDraggingEnabled} - disabled={isBulkEditEnabled} - > - <Combine className="mr-2 size-4" /> - {t("tags.drag_and_drop_merging")} - <InfoTooltip size={15} className="my-auto ml-2" variant="explain"> - <p>{t("tags.drag_and_drop_merging_info")}</p> - </InfoTooltip> - </Toggle> - <Toggle - variant="outline" - aria-label="Toggle bold" - pressed={sortByName} - onPressedChange={toggleSortByName} - > - <ArrowDownAZ className="mr-2 size-4" /> {t("tags.sort_by_name")} - </Toggle> - </div> - <span className="flex items-center gap-2"> - <p className="text-lg">{t("tags.your_tags")}</p> - <InfoTooltip size={15} className="my-auto" variant="explain"> - <p>{t("tags.your_tags_info")}</p> - </InfoTooltip> - </span> - {tagsToPill(humanTags, isBulkEditEnabled)} - <Separator /> - <span className="flex items-center gap-2"> - <p className="text-lg">{t("tags.ai_tags")}</p> - <InfoTooltip size={15} className="my-auto" variant="explain"> - <p>{t("tags.ai_tags_info")}</p> - </InfoTooltip> - </span> - {tagsToPill(aiTags, isBulkEditEnabled)} - <Separator /> - <span className="flex items-center gap-2"> - <p className="text-lg">{t("tags.unused_tags")}</p> - <InfoTooltip size={15} className="my-auto" variant="explain"> - <p>{t("tags.unused_tags_info")}</p> - </InfoTooltip> - </span> - <Collapsible> - <div className="space-x-1 pb-2"> - <CollapsibleTrigger asChild> - <Button variant="secondary" disabled={emptyTags.length == 0}> - {emptyTags.length > 0 - ? `Show ${emptyTags.length} unused tags` - : "You don't have any unused tags"} - </Button> - </CollapsibleTrigger> - {emptyTags.length > 0 && ( - <DeleteAllUnusedTags numUnusedTags={emptyTags.length} /> - )} + <div className="flex justify-between gap-x-2"> + <span className="text-2xl">{t("tags.all_tags")}</span> + <div className="flex gap-x-2"> + <BulkTagAction /> + <Toggle + variant="outline" + className="bg-background" + aria-label="Toggle bold" + pressed={draggingEnabled} + onPressedChange={toggleDraggingEnabled} + disabled={isBulkEditEnabled} + > + <Combine className="mr-2 size-4" /> + {t("tags.drag_and_drop_merging")} + <InfoTooltip size={15} className="my-auto ml-2" variant="explain"> + <p>{t("tags.drag_and_drop_merging_info")}</p> + </InfoTooltip> + </Toggle> + <Toggle + variant="outline" + className="bg-background" + aria-label="Toggle bold" + pressed={sortByName} + onPressedChange={toggleSortByName} + > + <ArrowDownAZ className="mr-2 size-4" /> {t("tags.sort_by_name")} + </Toggle> </div> - <CollapsibleContent> - {tagsToPill(emptyTags, isBulkEditEnabled)} - </CollapsibleContent> - </Collapsible> - </> + </div> + <Card> + <CardHeader> + <CardTitle className="flex items-center gap-2"> + <span>{t("tags.your_tags")}</span> + <Badge variant="secondary">{humanTags.length}</Badge> + </CardTitle> + <CardDescription>{t("tags.your_tags_info")}</CardDescription> + </CardHeader> + <CardContent>{tagsToPill(humanTags, isBulkEditEnabled)}</CardContent> + </Card> + <Card> + <CardHeader> + <CardTitle className="flex items-center gap-2"> + <span>{t("tags.ai_tags")}</span> + <Badge variant="secondary">{aiTags.length}</Badge> + </CardTitle> + <CardDescription>{t("tags.ai_tags_info")}</CardDescription> + </CardHeader> + <CardContent>{tagsToPill(aiTags, isBulkEditEnabled)}</CardContent> + </Card> + <Card> + <CardHeader> + <CardTitle>{t("tags.unused_tags")}</CardTitle> + <CardDescription>{t("tags.unused_tags_info")}</CardDescription> + </CardHeader> + <CardContent> + <Collapsible> + <div className="space-x-1 pb-2"> + <CollapsibleTrigger asChild> + <Button variant="secondary" disabled={emptyTags.length == 0}> + {emptyTags.length > 0 + ? `Show ${emptyTags.length} unused tags` + : "You don't have any unused tags"} + </Button> + </CollapsibleTrigger> + {emptyTags.length > 0 && ( + <DeleteAllUnusedTags numUnusedTags={emptyTags.length} /> + )} + </div> + <CollapsibleContent> + {tagsToPill(emptyTags, isBulkEditEnabled)} + </CollapsibleContent> + </Collapsible> + </CardContent> + </Card> + </div> ); } diff --git a/apps/web/components/dashboard/tags/BulkTagAction.tsx b/apps/web/components/dashboard/tags/BulkTagAction.tsx index 95f7c46d..fbd044e0 100644 --- a/apps/web/components/dashboard/tags/BulkTagAction.tsx +++ b/apps/web/components/dashboard/tags/BulkTagAction.tsx @@ -115,6 +115,7 @@ export default function BulkTagAction() { {!isBulkEditEnabled ? ( <Toggle variant="outline" + className="bg-background" aria-label="Toggle bulk edit" pressed={isBulkEditEnabled} onPressedChange={setIsBulkEditEnabled} @@ -123,13 +124,13 @@ export default function BulkTagAction() { {t("actions.bulk_edit")} </Toggle> ) : ( - <div className="flex items-center"> + <div className="flex items-center rounded-md bg-background"> {actionList.map(({ name, icon, action, alwaysEnable }) => ( <ButtonWithTooltip tooltip={name} disabled={!selectedTagIds.length && !alwaysEnable} delayDuration={100} - variant="ghost" + variant="none" key={name} onClick={action} > |
