custom icons fully implemented for collections
This commit is contained in:
parent
6df2e44213
commit
bf1a6efd2e
|
@ -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,
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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]"
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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';
|
|
@ -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")
|
||||||
|
|
Ŝarĝante…
Reference in New Issue