aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/components/dashboard
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/components/dashboard')
-rw-r--r--apps/web/components/dashboard/admin/AdminCard.tsx3
-rw-r--r--apps/web/components/dashboard/admin/AdminNotices.tsx71
-rw-r--r--apps/web/components/dashboard/bookmarks/BookmarkMarkdownComponent.tsx43
-rw-r--r--apps/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx67
-rw-r--r--apps/web/components/dashboard/bookmarks/TextCard.tsx11
-rw-r--r--apps/web/components/dashboard/header/ProfileOptions.tsx11
-rw-r--r--apps/web/components/dashboard/preview/TextContentSection.tsx7
7 files changed, 148 insertions, 65 deletions
diff --git a/apps/web/components/dashboard/admin/AdminCard.tsx b/apps/web/components/dashboard/admin/AdminCard.tsx
new file mode 100644
index 00000000..3a52b5e5
--- /dev/null
+++ b/apps/web/components/dashboard/admin/AdminCard.tsx
@@ -0,0 +1,3 @@
+export function AdminCard({ children }: { children: React.ReactNode }) {
+ return <div className="rounded-md border bg-background p-4">{children}</div>;
+}
diff --git a/apps/web/components/dashboard/admin/AdminNotices.tsx b/apps/web/components/dashboard/admin/AdminNotices.tsx
new file mode 100644
index 00000000..4977736f
--- /dev/null
+++ b/apps/web/components/dashboard/admin/AdminNotices.tsx
@@ -0,0 +1,71 @@
+"use client";
+
+import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
+import { Badge } from "@/components/ui/badge";
+import { api } from "@/lib/trpc";
+import { AlertCircle } from "lucide-react";
+
+import { AdminCard } from "./AdminCard";
+
+interface AdminNotice {
+ level: "info" | "warning" | "error";
+ message: React.ReactNode;
+ title: string;
+}
+
+function useAdminNotices() {
+ const { data } = api.admin.getAdminNoticies.useQuery();
+ if (!data) {
+ return [];
+ }
+ const ret: AdminNotice[] = [];
+ if (data.legacyContainersNotice) {
+ ret.push({
+ level: "warning",
+ message: (
+ <p>
+ You&apos;re using the legacy docker container images. Those will stop
+ getting supported soon. Please follow{" "}
+ <a
+ href="https://docs.hoarder.app/next/Guides/legacy-container-upgrade"
+ className="underline"
+ >
+ this guide
+ </a>{" "}
+ to upgrade.
+ </p>
+ ),
+ title: "Legacy Container Images",
+ });
+ }
+ return ret;
+}
+
+export function AdminNotices() {
+ const notices = useAdminNotices();
+
+ if (notices.length === 0) {
+ return null;
+ }
+ return (
+ <AdminCard>
+ <div className="flex flex-col gap-2">
+ {notices.map((n, i) => (
+ <Alert key={i} variant="destructive">
+ <AlertCircle className="h-4 w-4" />
+ <AlertTitle>{n.title}</AlertTitle>
+ <AlertDescription>{n.message}</AlertDescription>
+ </Alert>
+ ))}
+ </div>
+ </AdminCard>
+ );
+}
+
+export function AdminNoticeBadge() {
+ const notices = useAdminNotices();
+ if (notices.length === 0) {
+ return null;
+ }
+ return <Badge variant="destructive">{notices.length}</Badge>;
+}
diff --git a/apps/web/components/dashboard/bookmarks/BookmarkMarkdownComponent.tsx b/apps/web/components/dashboard/bookmarks/BookmarkMarkdownComponent.tsx
new file mode 100644
index 00000000..74eb0868
--- /dev/null
+++ b/apps/web/components/dashboard/bookmarks/BookmarkMarkdownComponent.tsx
@@ -0,0 +1,43 @@
+import MarkdownEditor from "@/components/ui/markdown/markdown-editor";
+import { MarkdownReadonly } from "@/components/ui/markdown/markdown-readonly";
+import { toast } from "@/components/ui/use-toast";
+
+import type { ZBookmarkTypeText } from "@hoarder/shared/types/bookmarks";
+import { useUpdateBookmarkText } from "@hoarder/shared-react/hooks/bookmarks";
+
+export function BookmarkMarkdownComponent({
+ children: bookmark,
+ readOnly = true,
+}: {
+ children: ZBookmarkTypeText;
+ readOnly?: boolean;
+}) {
+ const { mutate: updateBookmarkMutator, isPending } = useUpdateBookmarkText({
+ onSuccess: () => {
+ toast({
+ description: "Note updated!",
+ });
+ },
+ onError: () => {
+ toast({ description: "Something went wrong", variant: "destructive" });
+ },
+ });
+
+ const onSave = (text: string) => {
+ updateBookmarkMutator({
+ bookmarkId: bookmark.id,
+ text,
+ });
+ };
+ return (
+ <div className="h-full overflow-hidden">
+ {readOnly ? (
+ <MarkdownReadonly>{bookmark.content.text}</MarkdownReadonly>
+ ) : (
+ <MarkdownEditor onSave={onSave} isSaving={isPending}>
+ {bookmark.content.text}
+ </MarkdownEditor>
+ )}
+ </div>
+ );
+}
diff --git a/apps/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx b/apps/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx
index e0434943..b2c27c7e 100644
--- a/apps/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx
+++ b/apps/web/components/dashboard/bookmarks/BookmarkedTextEditor.tsx
@@ -1,20 +1,12 @@
-import { useState } from "react";
-import { ActionButton } from "@/components/ui/action-button";
-import { Button } from "@/components/ui/button";
+import { BookmarkMarkdownComponent } from "@/components/dashboard/bookmarks/BookmarkMarkdownComponent";
import {
Dialog,
- DialogClose,
DialogContent,
- DialogDescription,
- DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
-import { Textarea } from "@/components/ui/textarea";
-import { toast } from "@/components/ui/use-toast";
-import { useUpdateBookmarkText } from "@hoarder/shared-react/hooks/bookmarks";
-import { BookmarkTypes, ZBookmark } from "@hoarder/shared/types/bookmarks";
+import { ZBookmark, ZBookmarkTypeText } from "@hoarder/shared/types/bookmarks";
export function BookmarkedTextEditor({
bookmark,
@@ -26,55 +18,20 @@ export function BookmarkedTextEditor({
setOpen: (open: boolean) => void;
}) {
const isNewBookmark = bookmark === undefined;
- const [noteText, setNoteText] = useState(
- bookmark && bookmark.content.type == BookmarkTypes.TEXT
- ? bookmark.content.text
- : "",
- );
-
- const { mutate: updateBookmarkMutator, isPending } = useUpdateBookmarkText({
- onSuccess: () => {
- toast({
- description: "Note updated!",
- });
- setOpen(false);
- },
- onError: () => {
- toast({ description: "Something went wrong", variant: "destructive" });
- },
- });
-
- const onSave = () => {
- updateBookmarkMutator({
- bookmarkId: bookmark.id,
- text: noteText,
- });
- };
return (
<Dialog open={open} onOpenChange={setOpen}>
- <DialogContent>
- <DialogHeader>
- <DialogTitle>{isNewBookmark ? "New Note" : "Edit Note"}</DialogTitle>
- <DialogDescription>
- Write your note with markdown support
- </DialogDescription>
+ <DialogContent className="max-w-[80%]">
+ <DialogHeader className="flex">
+ <DialogTitle className="w-fit">
+ {isNewBookmark ? "New Note" : "Edit Note"}
+ </DialogTitle>
</DialogHeader>
- <Textarea
- value={noteText}
- onChange={(e) => setNoteText(e.target.value)}
- className="h-52 grow"
- />
- <DialogFooter className="flex-shrink gap-1 sm:justify-end">
- <DialogClose asChild>
- <Button type="button" variant="secondary">
- Close
- </Button>
- </DialogClose>
- <ActionButton type="button" loading={isPending} onClick={onSave}>
- Save
- </ActionButton>
- </DialogFooter>
+ <div className="h-[80vh]">
+ <BookmarkMarkdownComponent readOnly={false}>
+ {bookmark as ZBookmarkTypeText}
+ </BookmarkMarkdownComponent>
+ </div>
</DialogContent>
</Dialog>
);
diff --git a/apps/web/components/dashboard/bookmarks/TextCard.tsx b/apps/web/components/dashboard/bookmarks/TextCard.tsx
index 14a4f905..9d168910 100644
--- a/apps/web/components/dashboard/bookmarks/TextCard.tsx
+++ b/apps/web/components/dashboard/bookmarks/TextCard.tsx
@@ -2,7 +2,7 @@
import Image from "next/image";
import Link from "next/link";
-import { MarkdownComponent } from "@/components/ui/markdown-component";
+import { BookmarkMarkdownComponent } from "@/components/dashboard/bookmarks/BookmarkMarkdownComponent";
import { bookmarkLayoutSwitch } from "@/lib/userLocalSettings/bookmarksLayout";
import { cn } from "@/lib/utils";
@@ -20,15 +20,16 @@ export default function TextCard({
bookmark: ZBookmarkTypeText;
className?: string;
}) {
- const bookmarkedText = bookmark.content;
-
const banner = bookmark.assets.find((a) => a.assetType == "bannerImage");
-
return (
<>
<BookmarkLayoutAdaptingCard
title={bookmark.title}
- content={<MarkdownComponent>{bookmarkedText.text}</MarkdownComponent>}
+ content={
+ <BookmarkMarkdownComponent readOnly={true}>
+ {bookmark}
+ </BookmarkMarkdownComponent>
+ }
footer={
getSourceUrl(bookmark) && (
<FooterLinkURL url={getSourceUrl(bookmark)} />
diff --git a/apps/web/components/dashboard/header/ProfileOptions.tsx b/apps/web/components/dashboard/header/ProfileOptions.tsx
index 3dbfcf04..fc18e9d2 100644
--- a/apps/web/components/dashboard/header/ProfileOptions.tsx
+++ b/apps/web/components/dashboard/header/ProfileOptions.tsx
@@ -16,6 +16,8 @@ import { LogOut, Moon, Paintbrush, Settings, Shield, Sun } from "lucide-react";
import { signOut, useSession } from "next-auth/react";
import { useTheme } from "next-themes";
+import { AdminNoticeBadge } from "../admin/AdminNotices";
+
function DarkModeToggle() {
const { t } = useTranslation();
const { theme } = useTheme();
@@ -72,9 +74,12 @@ export default function SidebarProfileOptions() {
</DropdownMenuItem>
{session.user.role == "admin" && (
<DropdownMenuItem asChild>
- <Link href="/dashboard/admin">
- <Shield className="mr-2 size-4" />
- {t("admin.admin_settings")}
+ <Link href="/dashboard/admin" className="flex justify-between">
+ <div className="items-cente flex gap-2">
+ <Shield className="size-4" />
+ {t("admin.admin_settings")}
+ </div>
+ <AdminNoticeBadge />
</Link>
</DropdownMenuItem>
)}
diff --git a/apps/web/components/dashboard/preview/TextContentSection.tsx b/apps/web/components/dashboard/preview/TextContentSection.tsx
index 327436c6..a58bc717 100644
--- a/apps/web/components/dashboard/preview/TextContentSection.tsx
+++ b/apps/web/components/dashboard/preview/TextContentSection.tsx
@@ -1,7 +1,8 @@
import Image from "next/image";
-import { MarkdownComponent } from "@/components/ui/markdown-component";
+import { BookmarkMarkdownComponent } from "@/components/dashboard/bookmarks/BookmarkMarkdownComponent";
import { ScrollArea } from "@radix-ui/react-scroll-area";
+import type { ZBookmarkTypeText } from "@hoarder/shared/types/bookmarks";
import { getAssetUrl } from "@hoarder/shared-react/utils/assetUtils";
import { BookmarkTypes, ZBookmark } from "@hoarder/shared/types/bookmarks";
@@ -27,7 +28,9 @@ export function TextContentSection({ bookmark }: { bookmark: ZBookmark }) {
/>
</div>
)}
- <MarkdownComponent>{bookmark.content.text}</MarkdownComponent>
+ <BookmarkMarkdownComponent>
+ {bookmark as ZBookmarkTypeText}
+ </BookmarkMarkdownComponent>
</ScrollArea>
);
}