custom icons fully implemented for collections

This commit is contained in:
daniel31x13 2024-08-20 19:25:35 -04:00
parent 6df2e44213
commit bf1a6efd2e
11 changed files with 127 additions and 56 deletions

View File

@ -17,6 +17,8 @@ import toast from "react-hot-toast";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { useCollections, useUpdateCollection } from "@/hooks/store/collections"; import { useCollections, useUpdateCollection } from "@/hooks/store/collections";
import { useUpdateUser, useUser } from "@/hooks/store/user"; import { useUpdateUser, useUser } from "@/hooks/store/user";
import Icon from "./Icon";
import { IconWeight } from "@phosphor-icons/react";
interface ExtendedTreeItem extends TreeItem { interface ExtendedTreeItem extends TreeItem {
data: Collection; data: Collection;
@ -256,7 +258,7 @@ const renderItem = (
: "hover:bg-neutral/20" : "hover:bg-neutral/20"
} duration-100 flex gap-1 items-center pr-2 pl-1 rounded-md`} } duration-100 flex gap-1 items-center pr-2 pl-1 rounded-md`}
> >
{Icon(item as ExtendedTreeItem, onExpand, onCollapse)} {Dropdown(item as ExtendedTreeItem, onExpand, onCollapse)}
<Link <Link
href={`/collections/${collection.id}`} href={`/collections/${collection.id}`}
@ -266,10 +268,21 @@ const renderItem = (
<div <div
className={`py-1 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`} className={`py-1 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`}
> >
<i {collection.icon ? (
className="bi-folder-fill text-2xl drop-shadow" <Icon
style={{ color: collection.color }} icon={collection.icon}
></i> size={30}
weight={(collection.iconWeight || "regular") as IconWeight}
color={collection.color || "#0ea5e9"}
className="-mr-[0.15rem]"
/>
) : (
<i
className="bi-folder-fill text-2xl"
style={{ color: collection.color || "#0ea5e9" }}
></i>
)}
<p className="truncate w-full">{collection.name}</p> <p className="truncate w-full">{collection.name}</p>
{collection.isPublic && ( {collection.isPublic && (
@ -288,7 +301,7 @@ const renderItem = (
); );
}; };
const Icon = ( const Dropdown = (
item: ExtendedTreeItem, item: ExtendedTreeItem,
onExpand: (id: ItemId) => void, onExpand: (id: ItemId) => void,
onCollapse: (id: ItemId) => void onCollapse: (id: ItemId) => void
@ -332,6 +345,8 @@ const buildTreeFromCollections = (
name: collection.name, name: collection.name,
description: collection.description, description: collection.description,
color: collection.color, color: collection.color,
icon: collection.icon,
iconWeight: collection.iconWeight,
isPublic: collection.isPublic, isPublic: collection.isPublic,
ownerId: collection.ownerId, ownerId: collection.ownerId,
createdAt: collection.createdAt, createdAt: collection.createdAt,

View File

@ -20,6 +20,8 @@ import { useGetLink } from "@/hooks/store/links";
import LinkIcon from "./LinkViews/LinkComponents/LinkIcon"; import LinkIcon from "./LinkViews/LinkComponents/LinkIcon";
import CopyButton from "./CopyButton"; import CopyButton from "./CopyButton";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import Icon from "./Icon";
import { IconWeight } from "@phosphor-icons/react";
type Props = { type Props = {
className?: string; className?: string;
@ -163,10 +165,19 @@ export default function LinkDetails({ className, link }: Props) {
> >
<p>{link.collection.name}</p> <p>{link.collection.name}</p>
<div className="absolute right-0 px-2 bg-base-200"> <div className="absolute right-0 px-2 bg-base-200">
<i {link.collection.icon ? (
className="bi-folder-fill text-xl" <Icon
style={{ color: link.collection.color }} icon={link.collection.icon}
></i> size={30}
weight={(link.collection.iconWeight || "regular") as IconWeight}
color={link.collection.color || "#0ea5e9"}
/>
) : (
<i
className="bi-folder-fill text-2xl"
style={{ color: link.collection.color || "#0ea5e9" }}
></i>
)}
</div> </div>
</Link> </Link>
</div> </div>

View File

@ -1,7 +1,9 @@
import Icon from "@/components/Icon";
import { import {
CollectionIncludingMembersAndLinkCount, CollectionIncludingMembersAndLinkCount,
LinkIncludingShortenedCollectionAndTags, LinkIncludingShortenedCollectionAndTags,
} from "@/types/global"; } from "@/types/global";
import { IconWeight } from "@phosphor-icons/react";
import Link from "next/link"; import Link from "next/link";
import React from "react"; import React from "react";
@ -22,10 +24,19 @@ export default function LinkCollection({
className="flex items-center gap-1 max-w-full w-fit hover:opacity-70 duration-100 select-none" className="flex items-center gap-1 max-w-full w-fit hover:opacity-70 duration-100 select-none"
title={collection?.name} title={collection?.name}
> >
<i {link.collection.icon ? (
className="bi-folder-fill text-lg drop-shadow" <Icon
style={{ color: collection?.color }} icon={link.collection.icon}
></i> size={20}
weight={(link.collection.iconWeight || "regular") as IconWeight}
color={link.collection.color || "#0ea5e9"}
/>
) : (
<i
className="bi-folder-fill text-lg"
style={{ color: link.collection.color || "#0ea5e9" }}
></i>
)}
<p className="truncate capitalize">{collection?.name}</p> <p className="truncate capitalize">{collection?.name}</p>
</Link> </Link>
</> </>

View File

@ -6,7 +6,6 @@ import { useTranslation } from "next-i18next";
import { useUpdateCollection } from "@/hooks/store/collections"; import { useUpdateCollection } from "@/hooks/store/collections";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import IconPicker from "../IconPicker"; import IconPicker from "../IconPicker";
import Icon from "../Icon";
import { IconWeight } from "@phosphor-icons/react"; import { IconWeight } from "@phosphor-icons/react";
type Props = { type Props = {

View File

@ -1,12 +1,13 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import TextInput from "@/components/TextInput"; import TextInput from "@/components/TextInput";
import { HexColorPicker } from "react-colorful";
import { Collection } from "@prisma/client"; import { Collection } from "@prisma/client";
import Modal from "../Modal"; import Modal from "../Modal";
import { CollectionIncludingMembersAndLinkCount } from "@/types/global"; import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { useCreateCollection } from "@/hooks/store/collections"; import { useCreateCollection } from "@/hooks/store/collections";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import IconPicker from "../IconPicker";
import { IconWeight } from "@phosphor-icons/react";
type Props = { type Props = {
onClose: Function; onClose: Function;
@ -72,10 +73,32 @@ export default function NewCollectionModal({ onClose, parent }: Props) {
<div className="divider mb-3 mt-1"></div> <div className="divider mb-3 mt-1"></div>
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<div className="flex flex-col sm:flex-row gap-3"> <div className="flex flex-col gap-3">
<div className="w-full"> <div className="flex gap-3 items-end">
<p className="mb-2">{t("name")}</p> <IconPicker
<div className="flex flex-col gap-2"> color={collection.color || "#0ea5e9"}
setColor={(color: string) =>
setCollection({ ...collection, color })
}
weight={(collection.iconWeight || "regular") as IconWeight}
setWeight={(iconWeight: string) =>
setCollection({ ...collection, iconWeight })
}
iconName={collection.icon as string}
setIconName={(icon: string) =>
setCollection({ ...collection, icon })
}
reset={() =>
setCollection({
...collection,
color: "#0ea5e9",
icon: "",
iconWeight: "",
})
}
/>
<div className="w-full">
<p className="mb-2">{t("name")}</p>
<TextInput <TextInput
className="bg-base-200" className="bg-base-200"
value={collection.name} value={collection.name}
@ -84,31 +107,6 @@ export default function NewCollectionModal({ onClose, parent }: Props) {
setCollection({ ...collection, name: e.target.value }) setCollection({ ...collection, name: e.target.value })
} }
/> />
<div>
<p className="w-full mb-2">{t("color")}</p>
<div className="color-picker flex justify-between items-center">
<HexColorPicker
color={collection.color as string}
onChange={(color) =>
setCollection({ ...collection, color })
}
/>
<div className="flex flex-col gap-2 items-center w-32">
<i
className={"bi-folder-fill text-5xl"}
style={{ color: collection.color as string }}
></i>
<div
className="btn btn-ghost btn-xs"
onClick={() =>
setCollection({ ...collection, color: "#0ea5e9" })
}
>
{t("reset")}
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>

View File

@ -16,6 +16,8 @@ import LinkActions from "./LinkViews/LinkComponents/LinkActions";
import { useTranslation } from "next-i18next"; import { useTranslation } from "next-i18next";
import { useCollections } from "@/hooks/store/collections"; import { useCollections } from "@/hooks/store/collections";
import { useGetLink } from "@/hooks/store/links"; import { useGetLink } from "@/hooks/store/links";
import { IconWeight } from "@phosphor-icons/react";
import Icon from "./Icon";
type LinkContent = { type LinkContent = {
title: string; title: string;
@ -203,10 +205,21 @@ export default function ReadableView({ link }: Props) {
href={`/collections/${link?.collection.id}`} href={`/collections/${link?.collection.id}`}
className="flex items-center gap-1 cursor-pointer hover:opacity-60 duration-100 mr-2 z-10" className="flex items-center gap-1 cursor-pointer hover:opacity-60 duration-100 mr-2 z-10"
> >
<i {link.collection.icon ? (
className="bi-folder-fill drop-shadow text-2xl" <Icon
style={{ color: link?.collection.color as string }} icon={link.collection.icon}
></i> size={30}
weight={
(link.collection.iconWeight || "regular") as IconWeight
}
color={link.collection.color || "#0ea5e9"}
/>
) : (
<i
className="bi-folder-fill text-2xl"
style={{ color: link.collection.color || "#0ea5e9" }}
></i>
)}
<p <p
title={link?.collection.name} title={link?.collection.name}
className="text-lg truncate max-w-[12rem]" className="text-lg truncate max-w-[12rem]"

View File

@ -18,8 +18,6 @@ export default async function updateCollection(
if (!(collectionIsAccessible?.ownerId === userId)) if (!(collectionIsAccessible?.ownerId === userId))
return { response: "Collection is not accessible.", status: 401 }; return { response: "Collection is not accessible.", status: 401 };
console.log(data);
if (data.parentId) { if (data.parentId) {
if (data.parentId !== ("root" as any)) { if (data.parentId !== ("root" as any)) {
const findParentCollection = await prisma.collection.findUnique({ const findParentCollection = await prisma.collection.findUnique({
@ -61,6 +59,8 @@ export default async function updateCollection(
name: data.name.trim(), name: data.name.trim(),
description: data.description, description: data.description,
color: data.color, color: data.color,
icon: data.icon,
iconWeight: data.iconWeight,
isPublic: data.isPublic, isPublic: data.isPublic,
parent: parent:
data.parentId && data.parentId !== ("root" as any) data.parentId && data.parentId !== ("root" as any)

View File

@ -42,6 +42,8 @@ export default async function postCollection(
name: collection.name.trim(), name: collection.name.trim(),
description: collection.description, description: collection.description,
color: collection.color, color: collection.color,
icon: collection.icon,
iconWeight: collection.iconWeight,
parent: collection.parentId parent: collection.parentId
? { ? {
connect: { connect: {

View File

@ -24,6 +24,8 @@ import { useCollections } from "@/hooks/store/collections";
import { useUser } from "@/hooks/store/user"; import { useUser } from "@/hooks/store/user";
import { useLinks } from "@/hooks/store/links"; import { useLinks } from "@/hooks/store/links";
import Links from "@/components/LinkViews/Links"; import Links from "@/components/LinkViews/Links";
import Icon from "@/components/Icon";
import { IconWeight } from "@phosphor-icons/react";
export default function Index() { export default function Index() {
const { t } = useTranslation(); const { t } = useTranslation();
@ -110,10 +112,21 @@ export default function Index() {
{activeCollection && ( {activeCollection && (
<div className="flex gap-3 items-start justify-between"> <div className="flex gap-3 items-start justify-between">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<i {activeCollection.icon ? (
className="bi-folder-fill text-3xl drop-shadow" <Icon
style={{ color: activeCollection?.color as string }} icon={activeCollection.icon}
></i> size={45}
weight={
(activeCollection.iconWeight || "regular") as IconWeight
}
color={activeCollection.color || "#0ea5e9"}
/>
) : (
<i
className="bi-folder-fill text-3xl"
style={{ color: activeCollection.color || "#0ea5e9" }}
></i>
)}
<p className="sm:text-3xl text-2xl capitalize w-full py-1 break-words hyphens-auto font-thin"> <p className="sm:text-3xl text-2xl capitalize w-full py-1 break-words hyphens-auto font-thin">
{activeCollection?.name} {activeCollection?.name}

View File

@ -0,0 +1,9 @@
/*
Warnings:
- Made the column `color` on table `Collection` required. This step will fail if there are existing NULL values in that column.
*/
-- AlterTable
ALTER TABLE "Collection" ALTER COLUMN "color" SET NOT NULL,
ALTER COLUMN "color" SET DEFAULT '#0ea5e9';

View File

@ -96,7 +96,7 @@ model Collection {
description String @default("") description String @default("")
icon String? icon String?
iconWeight String? iconWeight String?
color String? color String @default("#0ea5e9")
parentId Int? parentId Int?
parent Collection? @relation("SubCollections", fields: [parentId], references: [id]) parent Collection? @relation("SubCollections", fields: [parentId], references: [id])
subCollections Collection[] @relation("SubCollections") subCollections Collection[] @relation("SubCollections")