make tags visible on public collections

This commit is contained in:
daniel31x13 2024-11-02 18:16:38 -04:00
parent d86bbcd940
commit 2e1e94112f
6 changed files with 102 additions and 127 deletions

View File

@ -130,31 +130,6 @@ export default function EditCollectionSharingModal({
</div> </div>
)} )}
{permissions === true && collection.isPublic && (
<div>
<p>Show tags in public collection</p>
<label className="label cursor-pointer justify-start gap-2">
<input
type="checkbox"
checked={collection.tagsArePublic}
onChange={() =>
setCollection({
...collection,
tagsArePublic: !collection.tagsArePublic,
})
}
className="checkbox checkbox-primary"
/>
<span className="label-text">Show tags in public collection</span>
</label>
<p className="text-neutral text-sm">
This will let <b>Anyone</b> view this collections tags and search
this collections links by them.
</p>
</div>
)}
{collection.isPublic && ( {collection.isPublic && (
<div> <div>
<p className="mb-2">{t("sharable_link")}</p> <p className="mb-2">{t("sharable_link")}</p>

View File

@ -84,7 +84,6 @@ export default async function updateCollection(
icon: data.icon, icon: data.icon,
iconWeight: data.iconWeight, iconWeight: data.iconWeight,
isPublic: data.isPublic, isPublic: data.isPublic,
tagsArePublic: data.tagsArePublic,
parent: parent:
data.parentId && data.parentId !== "root" data.parentId && data.parentId !== "root"
? { ? {

View File

@ -190,7 +190,6 @@ export const UpdateCollectionSchema = z.object({
isPublic: z.boolean().optional(), isPublic: z.boolean().optional(),
icon: z.string().trim().max(50).nullish(), icon: z.string().trim().max(50).nullish(),
iconWeight: z.string().trim().max(50).nullish(), iconWeight: z.string().trim().max(50).nullish(),
tagsArePublic: z.boolean().optional(),
parentId: z.union([z.number(), z.literal("root")]).nullish(), parentId: z.union([z.number(), z.literal("root")]).nullish(),
members: z.array( members: z.array(
z.object({ z.object({

View File

@ -25,11 +25,10 @@ import { usePublicLinks } from "@/hooks/store/publicLinks";
import Links from "@/components/LinkViews/Links"; import Links from "@/components/LinkViews/Links";
import { Disclosure, Transition } from "@headlessui/react"; import { Disclosure, Transition } from "@headlessui/react";
export default function PublicCollections() { export default function PublicCollections() {
const { t } = useTranslation(); const { t } = useTranslation();
const { settings } = useLocalSettingsStore(); const { settings } = useLocalSettingsStore();
const router = useRouter(); const router = useRouter();
@ -37,22 +36,31 @@ const { settings } = useLocalSettingsStore();
Partial<AccountSettings> Partial<AccountSettings>
>({}); >({});
const handleTagSelection = (tag: string | undefined) => { const handleTagSelection = (tag: string | undefined) => {
if (tag) { if (tag) {
Object.keys(searchFilter).forEach((v) => searchFilter[(v as keyof {name: boolean, url: boolean, description: boolean, tags: boolean, textContent: boolean})] = false) Object.keys(searchFilter).forEach(
(v) =>
(searchFilter[
v as keyof {
name: boolean;
url: boolean;
description: boolean;
tags: boolean;
textContent: boolean;
}
] = false)
);
searchFilter.tags = true; searchFilter.tags = true;
return router.push( return router.push(
"/public/collections/" + "/public/collections/" +
router.query.id + router.query.id +
"?q=" + "?q=" +
encodeURIComponent(tag || "") encodeURIComponent(tag || "")
); );
} else { } else {
return router.push( return router.push("/public/collections/" + router.query.id);
"/public/collections/" +
router.query.id)
} }
} };
const [searchFilter, setSearchFilter] = useState({ const [searchFilter, setSearchFilter] = useState({
name: true, name: true,
@ -106,18 +114,18 @@ const { settings } = useLocalSettingsStore();
(localStorage.getItem("viewMode") as ViewMode) || ViewMode.Card (localStorage.getItem("viewMode") as ViewMode) || ViewMode.Card
); );
const [tagDisclosure, setTagDisclosure] = useState<boolean>(() => { const [tagDisclosure, setTagDisclosure] = useState<boolean>(() => {
const storedValue = localStorage.getItem( const storedValue = localStorage.getItem(
"tagDisclosureForPublicCollection" + collection?.id "tagDisclosureForPublicCollection" + collection?.id
); );
return storedValue ? storedValue === "true" : true; return storedValue ? storedValue === "true" : true;
}); });
useEffect(() => { useEffect(() => {
localStorage.setItem( localStorage.setItem(
"tagDisclosureForPublicCollection" + collection?.id, "tagDisclosureForPublicCollection" + collection?.id,
tagDisclosure ? "true" : "false" tagDisclosure ? "true" : "false"
); );
}, [tagDisclosure]); }, [tagDisclosure]);
if (!collection) return <></>; if (!collection) return <></>;
else else
@ -243,88 +251,85 @@ useEffect(() => {
} }
/> />
</LinkListOptions> </LinkListOptions>
{collection.tagsArePublic && {linksForWholeCollection?.flatMap((l) => l.tags)[0] && (
linksForWholeCollection?.flatMap((l) => l.tags)[0] && ( <Disclosure defaultOpen={tagDisclosure}>
<Disclosure defaultOpen={tagDisclosure}> <Disclosure.Button
<Disclosure.Button onClick={() => {
onClick={() => { setTagDisclosure(!tagDisclosure);
setTagDisclosure(!tagDisclosure); }}
}} className="flex items-center justify-between w-full text-left mb-2 pl-2 font-bold text-neutral mt-5"
className="flex items-center justify-between w-full text-left mb-2 pl-2 font-bold text-neutral mt-5" >
> <p className="text-sm">{t("browse_by_topic")}</p>
<p className="text-sm">{t("browse_by_topic")}</p> <i
<i className={`bi-chevron-down ${
className={`bi-chevron-down ${ tagDisclosure ? "rotate-reverse" : "rotate"
tagDisclosure ? "rotate-reverse" : "rotate" }`}
}`} ></i>
></i> </Disclosure.Button>
</Disclosure.Button> <Transition
<Transition enter="transition duration-100 ease-out"
enter="transition duration-100 ease-out" enterFrom="transform opacity-0 -translate-y-3"
enterFrom="transform opacity-0 -translate-y-3" enterTo="transform opacity-100 translate-y-0"
enterTo="transform opacity-100 translate-y-0" leave="transition duration-100 ease-out"
leave="transition duration-100 ease-out" leaveFrom="transform opacity-100 translate-y-0"
leaveFrom="transform opacity-100 translate-y-0" leaveTo="transform opacity-0 -translate-y-3"
leaveTo="transform opacity-0 -translate-y-3" >
> <Disclosure.Panel>
<Disclosure.Panel> <div className="flex gap-2 mt-2 mb-6 flex-wrap">
<div className="flex gap-2 mt-2 mb-6 flex-wrap"> <button
<button className="max-w-full"
className="max-w-full" onClick={() => handleTagSelection(undefined)}
onClick={() => handleTagSelection(undefined)} >
> <div
<div className="
className="
bg-neutral-content/20 hover:bg-neutral/20 duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 rounded-md h-8" bg-neutral-content/20 hover:bg-neutral/20 duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 rounded-md h-8"
> >
<i className="text-primary bi-hash text-2xl text-primary drop-shadow"></i> <i className="text-primary bi-hash text-2xl text-primary drop-shadow"></i>
<p className="truncate pr-7">{t("all_links")}</p> <p className="truncate pr-7">{t("all_links")}</p>
<div className="text-neutral drop-shadow text-neutral text-xs"> <div className="text-neutral drop-shadow text-neutral text-xs">
{collection._count?.links} {collection._count?.links}
</div>
</div> </div>
</button> </div>
{linksForWholeCollection </button>
.flatMap((l) => l.tags) {linksForWholeCollection
.map((t) => t.name) .flatMap((l) => l.tags)
.filter( .map((t) => t.name)
(item, pos, self) => self.indexOf(item) === pos .filter((item, pos, self) => self.indexOf(item) === pos)
) .sort((a, b) => a.localeCompare(b))
.sort((a, b) => a.localeCompare(b)) .map((e, i) => {
.map((e, i) => { const active = router.query.q === e;
const active = router.query.q === e; return (
return ( <button
<button className="max-w-full"
className="max-w-full" key={i}
key={i} onClick={() => handleTagSelection(e)}
onClick={() => handleTagSelection(e)} >
> <div
<div className={`
className={`
${ ${
active active
? "bg-primary/20" ? "bg-primary/20"
: "bg-neutral-content/20 hover:bg-neutral/20" : "bg-neutral-content/20 hover:bg-neutral/20"
} duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 rounded-md h-8`} } duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 rounded-md h-8`}
> >
<i className="bi-hash text-2xl text-primary drop-shadow"></i> <i className="bi-hash text-2xl text-primary drop-shadow"></i>
<p className="truncate pr-7">{e}</p> <p className="truncate pr-7">{e}</p>
<div className="drop-shadow text-neutral text-xs"> <div className="drop-shadow text-neutral text-xs">
{ {
linksForWholeCollection.filter((l) => linksForWholeCollection.filter((l) =>
l.tags.map((t) => t.name).includes(e) l.tags.map((t) => t.name).includes(e)
).length ).length
} }
</div>
</div> </div>
</button> </div>
); </button>
})} );
</div> })}
</Disclosure.Panel> </div>
</Transition> </Disclosure.Panel>
</Disclosure> </Transition>
)} </Disclosure>
)}
<Links <Links
links={ links={
links?.map((e, i) => { links?.map((e, i) => {

View File

@ -1,2 +0,0 @@
-- AlterTable
ALTER TABLE "Collection" ADD COLUMN "tagsArePublic" BOOLEAN NOT NULL DEFAULT false;

View File

@ -105,7 +105,6 @@ model Collection {
parent Collection? @relation("SubCollections", fields: [parentId], references: [id]) parent Collection? @relation("SubCollections", fields: [parentId], references: [id])
subCollections Collection[] @relation("SubCollections") subCollections Collection[] @relation("SubCollections")
isPublic Boolean @default(false) isPublic Boolean @default(false)
tagsArePublic Boolean @default(false)
owner User @relation(fields: [ownerId], references: [id]) owner User @relation(fields: [ownerId], references: [id])
ownerId Int ownerId Int
members UsersAndCollections[] members UsersAndCollections[]