mirror of
https://github.com/linkwarden/linkwarden.git
synced 2026-06-28 14:55:49 +00:00
159 lines
5.0 KiB
TypeScript
159 lines
5.0 KiB
TypeScript
import {
|
|
DropdownMenu,
|
|
DropdownMenuTrigger,
|
|
DropdownMenuContent,
|
|
DropdownMenuCheckboxItem,
|
|
DropdownMenuSeparator,
|
|
} from "@/components/ui/dropdown-menu";
|
|
import useLocalSettingsStore from "@/store/localSettings";
|
|
import { ViewMode } from "@linkwarden/types/global";
|
|
import { useTranslation } from "next-i18next";
|
|
import { Button } from "@/components/ui/button";
|
|
import { useEffect } from "react";
|
|
|
|
type Props = {
|
|
viewMode: ViewMode;
|
|
setViewMode: React.Dispatch<React.SetStateAction<ViewMode>>;
|
|
dashboard?: boolean;
|
|
};
|
|
|
|
export default function ViewDropdown({
|
|
viewMode,
|
|
setViewMode,
|
|
dashboard,
|
|
}: Props) {
|
|
const { settings, updateSettings } = useLocalSettingsStore((s) => s);
|
|
const { t } = useTranslation();
|
|
|
|
useEffect(() => {
|
|
updateSettings({ viewMode });
|
|
}, [viewMode, updateSettings]);
|
|
|
|
const onChangeViewMode = (mode: ViewMode) => {
|
|
setViewMode(mode);
|
|
updateSettings({ viewMode: mode });
|
|
};
|
|
|
|
const toggleShow = (key: keyof typeof settings.show) => {
|
|
updateSettings({
|
|
show: { ...settings.show, [key]: !settings.show[key] },
|
|
});
|
|
};
|
|
|
|
const onColumnsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
updateSettings({ columns: Number(e.target.value) });
|
|
};
|
|
|
|
const visibleShows = (
|
|
Object.keys(settings.show) as (keyof typeof settings.show)[]
|
|
).filter((key) => {
|
|
if (!dashboard && settings.viewMode === ViewMode.List)
|
|
return key !== "tags" && key !== "image" && key !== "description";
|
|
if (dashboard || settings.viewMode === ViewMode.Card)
|
|
return key !== "tags" && key !== "description";
|
|
return true;
|
|
});
|
|
|
|
return (
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button variant="ghost" size="icon">
|
|
{dashboard || viewMode === ViewMode.Card ? (
|
|
<i className="bi-grid text-neutral"></i>
|
|
) : viewMode === ViewMode.Masonry ? (
|
|
<i className="bi-columns-gap text-neutral"></i>
|
|
) : (
|
|
<i className="bi-view-stacked text-neutral"></i>
|
|
)}
|
|
</Button>
|
|
</DropdownMenuTrigger>
|
|
|
|
<DropdownMenuContent sideOffset={4} align="end">
|
|
{!dashboard && (
|
|
<>
|
|
<div className="px-1">
|
|
<p className="text-xs font-bold text-neutral mb-1">{t("view")}</p>
|
|
<div className="flex gap-1 border-border">
|
|
{[ViewMode.Card, ViewMode.Masonry, ViewMode.List].map(
|
|
(mode) => {
|
|
const Icon =
|
|
mode === ViewMode.Card
|
|
? () => <i className="bi-grid w-4 h-4 text-neutral" />
|
|
: mode === ViewMode.Masonry
|
|
? () => (
|
|
<i className="bi-columns-gap w-4 h-4 text-neutral" />
|
|
)
|
|
: () => (
|
|
<i className="bi-view-stacked w-4 h-4 text-neutral" />
|
|
);
|
|
|
|
return (
|
|
<Button
|
|
key={mode}
|
|
variant="ghost"
|
|
size="sm"
|
|
onClick={() => onChangeViewMode(mode)}
|
|
className={
|
|
`flex-1 ` +
|
|
(viewMode === mode
|
|
? "bg-primary/20 hover:bg-primary/20"
|
|
: "hover:bg-neutral/20")
|
|
}
|
|
>
|
|
<Icon />
|
|
</Button>
|
|
);
|
|
}
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<DropdownMenuSeparator />
|
|
</>
|
|
)}
|
|
|
|
<p className="text-xs font-bold text-neutral px-1 mb-1">{t("show")}</p>
|
|
{visibleShows.map((key) => (
|
|
<DropdownMenuCheckboxItem
|
|
key={key}
|
|
checked={settings.show[key]}
|
|
onSelect={(e) => {
|
|
e.preventDefault();
|
|
toggleShow(key);
|
|
}}
|
|
>
|
|
{t(key)}
|
|
</DropdownMenuCheckboxItem>
|
|
))}
|
|
|
|
{!dashboard && settings.viewMode !== ViewMode.List && (
|
|
<>
|
|
<DropdownMenuSeparator />
|
|
|
|
<div className="px-1">
|
|
<p className="text-xs font-bold text-neutral mb-1">
|
|
{t("columns")}:{" "}
|
|
{settings.columns === 0 ? t("default") : settings.columns}
|
|
</p>
|
|
<input
|
|
type="range"
|
|
min={0}
|
|
max={8}
|
|
step={1}
|
|
value={settings.columns}
|
|
onChange={onColumnsChange}
|
|
className="range range-xs range-primary w-full"
|
|
/>
|
|
<div className="flex justify-between text-xs text-neutral select-none px-1">
|
|
{Array.from({ length: 9 }).map((_, i) => (
|
|
<span key={i}>|</span>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</>
|
|
)}
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
);
|
|
}
|