refactored view dropdown

This commit is contained in:
daniel31x13 2024-08-26 18:47:10 -04:00
parent 642374c2e5
commit 9ae9c7c81a
6 changed files with 191 additions and 82 deletions

View File

@ -23,6 +23,7 @@ import { useCollections } from "@/hooks/store/collections";
import { useUser } from "@/hooks/store/user";
import { useGetLink, useLinks } from "@/hooks/store/links";
import { useRouter } from "next/router";
import useLocalSettingsStore from "@/store/localSettings";
type Props = {
link: LinkIncludingShortenedCollectionAndTags;
@ -41,6 +42,10 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) {
const { setSelectedLinks, selectedLinks } = useLinkStore();
const {
settings: { show },
} = useLocalSettingsStore();
const {
data: { data: links = [] },
} = useLinks();
@ -166,11 +171,9 @@ export default function LinkCard({ link, flipDropdown, editMode }: Props) {
) : (
<div className="duration-100 h-40 bg-opacity-80 skeleton rounded-none"></div>
)}
{link.type !== "image" && (
<div className="absolute top-0 left-0 right-0 bottom-0 rounded-t-2xl flex items-center justify-center shadow rounded-md">
<LinkIcon link={link} />
</div>
)}
<div className="absolute top-0 left-0 right-0 bottom-0 rounded-t-2xl flex items-center justify-center shadow rounded-md">
<LinkIcon link={link} />
</div>
</div>
<hr className="divider my-0 border-t border-neutral-content h-[1px]" />
</div>

View File

@ -155,11 +155,9 @@ export default function LinkMasonry({ link, flipDropdown, editMode }: Props) {
) : link.preview === "unavailable" ? null : (
<div className="duration-100 h-40 bg-opacity-80 skeleton rounded-none"></div>
)}
{link.type !== "image" && (
<div className="absolute top-0 left-0 right-0 bottom-0 rounded-t-2xl flex items-center justify-center shadow rounded-md">
<LinkIcon link={link} />
</div>
)}
<div className="absolute top-0 left-0 right-0 bottom-0 rounded-t-2xl flex items-center justify-center shadow rounded-md">
<LinkIcon link={link} />
</div>
</div>
{link.preview !== "unavailable" && (

View File

@ -1,7 +1,8 @@
import React, { Dispatch, SetStateAction, useEffect } from "react";
import useLocalSettingsStore from "@/store/localSettings";
import { ViewMode } from "@/types/global";
import { dropdownTriggerer } from "@/lib/client/utils";
import { useTranslation } from "next-i18next";
type Props = {
viewMode: ViewMode;
@ -9,53 +10,111 @@ type Props = {
};
export default function ViewDropdown({ viewMode, setViewMode }: Props) {
const { updateSettings } = useLocalSettingsStore();
const { settings, updateSettings } = useLocalSettingsStore((state) => state);
const { t } = useTranslation();
const onChangeViewMode = (
e: React.MouseEvent<HTMLButtonElement>,
viewMode: ViewMode
mode: ViewMode
) => {
setViewMode(viewMode);
setViewMode(mode);
};
const toggleShowSetting = (setting: keyof typeof settings.show) => {
const newShowSettings = {
...settings.show,
[setting]: !settings.show[setting],
};
updateSettings({ show: newShowSettings });
};
useEffect(() => {
updateSettings({ viewMode });
}, [viewMode]);
}, [viewMode, updateSettings]);
return (
<div className="p-1 flex flex-row gap-1 border border-neutral-content rounded-[0.625rem]">
<button
onClick={(e) => onChangeViewMode(e, ViewMode.Card)}
className={`btn btn-square btn-sm btn-ghost ${
viewMode == ViewMode.Card
? "bg-primary/20 hover:bg-primary/20"
: "hover:bg-neutral/20"
}`}
<div className="dropdown dropdown-bottom dropdown-end">
<div
tabIndex={0}
role="button"
onMouseDown={dropdownTriggerer}
className="btn btn-sm btn-square btn-ghost border-none"
>
<i className="bi-grid w-4 h-4 text-neutral"></i>
</button>
<button
onClick={(e) => onChangeViewMode(e, ViewMode.Masonry)}
className={`btn btn-square btn-sm btn-ghost ${
viewMode == ViewMode.Masonry
? "bg-primary/20 hover:bg-primary/20"
: "hover:bg-neutral/20"
}`}
>
<i className="bi bi-columns-gap w-4 h-4 text-neutral"></i>
</button>
<button
onClick={(e) => onChangeViewMode(e, ViewMode.List)}
className={`btn btn-square btn-sm btn-ghost ${
viewMode == ViewMode.List
? "bg-primary/20 hover:bg-primary/20"
: "hover:bg-neutral/20"
}`}
>
<i className="bi bi-view-stacked w-4 h-4 text-neutral"></i>
</button>
{viewMode === ViewMode.Card ? (
<i className="bi-grid w-4 h-4 text-neutral"></i>
) : viewMode === ViewMode.Masonry ? (
<i className="bi-columns-gap w-4 h-4 text-neutral"></i>
) : (
<i className="bi-view-stacked w-4 h-4 text-neutral"></i>
)}
</div>
<ul className="dropdown-content z-[30] menu shadow bg-base-200 min-w-52 border border-neutral-content rounded-xl mt-1">
<p className="mb-1 text-sm text-neutral">{t("view")}</p>
<div
className="p-1 flex w-full justify-between gap-1 border border-neutral-content rounded-[0.625rem]"
tabIndex={0}
role="button"
>
<button
onClick={(e) => onChangeViewMode(e, ViewMode.Card)}
className={`btn btn-square btn-sm btn-ghost ${
viewMode === ViewMode.Card
? "bg-primary/20 hover:bg-primary/20"
: "hover:bg-neutral/20"
}`}
>
<i className="bi-grid text-lg text-neutral"></i>
</button>
<button
onClick={(e) => onChangeViewMode(e, ViewMode.Masonry)}
className={`btn btn-square btn-sm btn-ghost ${
viewMode === ViewMode.Masonry
? "bg-primary/20 hover:bg-primary/20"
: "hover:bg-neutral/20"
}`}
>
<i className="bi-columns-gap text-lg text-neutral"></i>
</button>
<button
onClick={(e) => onChangeViewMode(e, ViewMode.List)}
className={`btn btn-square btn-sm btn-ghost ${
viewMode === ViewMode.List
? "bg-primary/20 hover:bg-primary/20"
: "hover:bg-neutral/20"
}`}
>
<i className="bi-view-stacked text-lg text-neutral"></i>
</button>
</div>
<p className="my-1 text-sm text-neutral">{t("show")}</p>
{Object.entries(settings.show)
.filter((e) =>
settings.viewMode === ViewMode.List // Hide tags and image checkbox in list view
? e[0] !== "tags" && e[0] !== "image"
: settings.viewMode === ViewMode.Card // Hide tags checkbox in card view
? e[0] !== "tags"
: true
)
.map(([key, value]) => (
<li key={key}>
<label
className="label cursor-pointer flex justify-start"
tabIndex={0}
role="button"
>
<input
type="checkbox"
className="checkbox checkbox-primary"
checked={value}
onChange={() =>
toggleShowSetting(key as keyof typeof settings.show)
}
/>
<span className="label-text whitespace-nowrap">{t(key)}</span>
</label>
</li>
))}
</ul>
</div>
);
}

View File

@ -11,8 +11,8 @@ export const icons: ReadonlyArray<IconEntry> = iconData.map((entry) => ({
Icon: Icons[entry.pascal_name as keyof typeof Icons] as Icons.Icon,
}));
if (process.env.NODE_ENV === "development") {
console.log(`${icons.length} icons`);
}
// if (process.env.NODE_ENV === "development") {
// console.log(`${icons.length} icons`);
// }
export const iconCount = Intl.NumberFormat("en-US").format(icons.length * 6);

View File

@ -380,5 +380,10 @@
"duotone": "Duotone",
"light_icon": "Light",
"search": "Search",
"set_custom_icon": "Set Custom Icon"
"set_custom_icon": "Set Custom Icon",
"view": "View",
"show": "Show",
"image": "Image",
"icon": "Icon",
"date": "Date"
}

View File

@ -2,14 +2,24 @@ import { Sort } from "@/types/global";
import { create } from "zustand";
type LocalSettings = {
theme?: string;
viewMode?: string;
theme: string;
viewMode: string;
show: {
link: boolean;
title: boolean;
description: boolean;
image: boolean;
tags: boolean;
icon: boolean;
collection: boolean;
date: boolean;
};
sortBy?: Sort;
};
type LocalSettingsStore = {
settings: LocalSettings;
updateSettings: (settings: LocalSettings) => void;
updateSettings: (settings: Partial<LocalSettings>) => void;
setSettings: () => void;
};
@ -17,50 +27,84 @@ const useLocalSettingsStore = create<LocalSettingsStore>((set) => ({
settings: {
theme: "",
viewMode: "",
show: {
link: true,
title: true,
description: true,
image: true,
tags: true,
icon: true,
collection: true,
date: true,
},
sortBy: Sort.DateNewestFirst,
},
updateSettings: async (newSettings) => {
if (
newSettings.theme !== undefined &&
newSettings.theme !== localStorage.getItem("theme")
) {
localStorage.setItem("theme", newSettings.theme);
updateSettings: (newSettings) => {
const { theme, viewMode, sortBy, show } = newSettings;
const localTheme = localStorage.getItem("theme") || "";
document.querySelector("html")?.setAttribute("data-theme", localTheme);
if (theme !== undefined && theme !== localStorage.getItem("theme")) {
localStorage.setItem("theme", theme);
document.querySelector("html")?.setAttribute("data-theme", theme);
}
if (
newSettings.viewMode !== undefined &&
newSettings.viewMode !== localStorage.getItem("viewMode")
viewMode !== undefined &&
viewMode !== localStorage.getItem("viewMode")
) {
localStorage.setItem("viewMode", newSettings.viewMode);
// const localTheme = localStorage.getItem("viewMode") || "";
localStorage.setItem("viewMode", viewMode);
}
if (
newSettings.sortBy !== undefined &&
newSettings.sortBy !== Number(localStorage.getItem("sortBy"))
) {
localStorage.setItem("sortBy", newSettings.sortBy.toString());
if (sortBy !== undefined) {
localStorage.setItem("sortBy", sortBy.toString());
}
set((state) => ({ settings: { ...state.settings, ...newSettings } }));
},
setSettings: async () => {
if (!localStorage.getItem("theme")) {
localStorage.setItem("theme", "dark");
}
const currentShowString = localStorage.getItem("show");
const newShowString = show ? JSON.stringify(show) : currentShowString;
const localTheme = localStorage.getItem("theme") || "";
if (newShowString !== currentShowString) {
localStorage.setItem("show", newShowString || "");
}
set((state) => ({
settings: { ...state.settings, theme: localTheme },
settings: {
...state.settings,
...newSettings,
show: show ? { ...state.settings.show, ...show } : state.settings.show,
},
}));
},
setSettings: () => {
const theme = localStorage.getItem("theme") || "dark";
localStorage.setItem("theme", theme);
document.querySelector("html")?.setAttribute("data-theme", localTheme);
const viewMode = localStorage.getItem("viewMode") || "card";
localStorage.setItem("viewMode", viewMode);
const storedShow = localStorage.getItem("show");
const show = storedShow
? JSON.parse(storedShow)
: {
link: true,
name: true,
description: true,
image: true,
tags: true,
icon: true,
collection: true,
date: true,
};
localStorage.setItem("show", JSON.stringify(show));
set({
settings: {
theme,
viewMode,
show,
sortBy: useLocalSettingsStore.getState().settings.sortBy,
},
});
document.querySelector("html")?.setAttribute("data-theme", theme);
},
}));