diff --git a/components/Icon.tsx b/components/Icon.tsx new file mode 100644 index 0000000..178b9e6 --- /dev/null +++ b/components/Icon.tsx @@ -0,0 +1,16 @@ +import React, { forwardRef } from "react"; +import * as Icons from "@phosphor-icons/react"; + +type Props = { + icon: string; +} & Icons.IconProps; + +const Icon = forwardRef(({ icon, ...rest }) => { + const IconComponent: any = Icons[icon as keyof typeof Icons]; + + if (!IconComponent) { + return <>; + } else return ; +}); + +export default Icon; diff --git a/components/IconPicker.tsx b/components/IconPicker.tsx index 994a5af..f90dc1f 100644 --- a/components/IconPicker.tsx +++ b/components/IconPicker.tsx @@ -2,6 +2,9 @@ import { icons } from "@/lib/client/icons"; import React, { useMemo, useState } from "react"; import Fuse from "fuse.js"; import TextInput from "./TextInput"; +import Popover from "./Popover"; +import { HexColorPicker } from "react-colorful"; +import Icon from "./Icon"; const fuse = new Fuse(icons, { keys: [{ name: "name", weight: 4 }, "tags", "categories"], @@ -9,9 +12,29 @@ const fuse = new Fuse(icons, { useExtendedSearch: true, }); -type Props = {}; +type Props = { + onClose: Function; + alignment?: "left" | "right" | "bottom" | "top"; + color: string; + setColor: Function; + iconName: string; + setIconName: Function; + weight: "light" | "regular" | "bold" | "fill" | "duotone"; + setWeight: Function; + className?: string; +}; -const IconPicker = (props: Props) => { +const IconPicker = ({ + onClose, + alignment, + color, + setColor, + iconName, + setIconName, + weight, + setWeight, + className, +}: Props) => { const [query, setQuery] = useState(""); const filteredQueryResultsSelector = useMemo(() => { @@ -22,24 +45,67 @@ const IconPicker = (props: Props) => { }, [query]); return ( -
- setQuery(e.target.value)} - /> -
- {filteredQueryResultsSelector.map((icon) => { - const IconComponent = icon.Icon; - return ( -
console.log(icon.name)}> - -
- ); - })} + +
+
+
+ + + +
+ setColor(e)} /> +
+ + setQuery(e.target.value)} + /> + +
+ {filteredQueryResultsSelector.map((icon) => { + const IconComponent = icon.Icon; + return ( +
setIconName(icon.pascal_name)} + className={`cursor-pointer btn p-1 box-border ${ + icon.pascal_name === iconName + ? "outline outline-1 outline-primary" + : "" + }`} + > + +
+ ); + })} +
-
+ ); }; diff --git a/components/LinkViews/LinkComponents/LinkActions.tsx b/components/LinkViews/LinkComponents/LinkActions.tsx index f93f969..0e04491 100644 --- a/components/LinkViews/LinkComponents/LinkActions.tsx +++ b/components/LinkViews/LinkComponents/LinkActions.tsx @@ -105,24 +105,23 @@ export default function LinkActions({ alignToTop ? "" : "translate-y-10" }`} > - {permissions === true || - (permissions?.canUpdate && ( -
  • -
    { - (document?.activeElement as HTMLElement)?.blur(); - pinLink(); - }} - className="whitespace-nowrap" - > - {link?.pinnedBy && link.pinnedBy[0] - ? t("unpin") - : t("pin_to_dashboard")} -
    -
  • - ))} + {(permissions === true || permissions?.canUpdate) && ( +
  • +
    { + (document?.activeElement as HTMLElement)?.blur(); + pinLink(); + }} + className="whitespace-nowrap" + > + {link?.pinnedBy && link.pinnedBy[0] + ? t("unpin") + : t("pin_to_dashboard")} +
    +
  • + )}
  • { (document?.activeElement as HTMLElement)?.blur(); + console.log(e.shiftKey); e.shiftKey - ? async () => { + ? (async () => { const load = toast.loading(t("deleting")); await deleteLink.mutateAsync(link.id as number, { @@ -188,7 +188,7 @@ export default function LinkActions({ } }, }); - } + })() : setDeleteLinkModal(true); }} className="whitespace-nowrap" diff --git a/components/ModalContent/EditCollectionModal.tsx b/components/ModalContent/EditCollectionModal.tsx index f8dfd20..76833e7 100644 --- a/components/ModalContent/EditCollectionModal.tsx +++ b/components/ModalContent/EditCollectionModal.tsx @@ -6,6 +6,8 @@ import Modal from "../Modal"; import { useTranslation } from "next-i18next"; import { useUpdateCollection } from "@/hooks/store/collections"; import toast from "react-hot-toast"; +import IconPicker from "../IconPicker"; +import Icon from "../Icon"; type Props = { onClose: Function; @@ -20,6 +22,7 @@ export default function EditCollectionModal({ const [collection, setCollection] = useState(activeCollection); + const [iconPicker, setIconPicker] = useState(false); const [submitLoader, setSubmitLoader] = useState(false); const updateCollection = useUpdateCollection(); @@ -71,17 +74,32 @@ export default function EditCollectionModal({

    {t("color")}

    - - setCollection({ ...collection, color }) - } - /> -
    - +
    + setIconPicker(true)} + /> + {iconPicker && ( + setIconPicker(false)} + className="top-20" + color={collection.color as string} + setColor={(color: string) => + setCollection({ ...collection, color }) + } + weight={collection.iconWeight as any} + setWeight={(iconWeight: string) => + setCollection({ ...collection, iconWeight }) + } + iconName={collection.icon as string} + setIconName={(icon: string) => + setCollection({ ...collection, icon }) + } + /> + )}
    diff --git a/components/ModalContent/LinkDetailModal.tsx b/components/ModalContent/LinkDetailModal.tsx index e9f0086..ad7d36c 100644 --- a/components/ModalContent/LinkDetailModal.tsx +++ b/components/ModalContent/LinkDetailModal.tsx @@ -120,25 +120,24 @@ export default function LinkDetailModal({ onClose, onEdit, link }: Props) {
    - {permissions === true || - (permissions?.canUpdate && ( - <> -
    -
    + {(permissions === true || permissions?.canUpdate) && ( + <> +
    +
    -
    -
    { - onEdit(); - onClose(); - }} - > - {t("edit_link")} -
    +
    +
    { + onEdit(); + onClose(); + }} + > + {t("edit_link")}
    - - ))} +
    + + )}
    ); diff --git a/components/ModalContent/NewCollectionModal.tsx b/components/ModalContent/NewCollectionModal.tsx index df9d9bb..32cb5f9 100644 --- a/components/ModalContent/NewCollectionModal.tsx +++ b/components/ModalContent/NewCollectionModal.tsx @@ -88,7 +88,7 @@ export default function NewCollectionModal({ onClose, parent }: Props) {

    {t("color")}

    setCollection({ ...collection, color }) } @@ -96,7 +96,7 @@ export default function NewCollectionModal({ onClose, parent }: Props) {
    { + return ( + onClose()} + className={`absolute z-50 ${className || ""}`} + > + {children} + + ); +}; + +export default Popover; diff --git a/components/ReadableView.tsx b/components/ReadableView.tsx index 18477a0..11954b6 100644 --- a/components/ReadableView.tsx +++ b/components/ReadableView.tsx @@ -205,7 +205,7 @@ export default function ReadableView({ link }: Props) { >

    diff --git a/prisma/migrations/20240819003838_add_icon_related_fields_to_link_and_collection_model/migration.sql b/prisma/migrations/20240819003838_add_icon_related_fields_to_link_and_collection_model/migration.sql new file mode 100644 index 0000000..e208342 --- /dev/null +++ b/prisma/migrations/20240819003838_add_icon_related_fields_to_link_and_collection_model/migration.sql @@ -0,0 +1,8 @@ +-- AlterTable +ALTER TABLE "Collection" ADD COLUMN "icon" TEXT, +ADD COLUMN "iconWeight" TEXT; + +-- AlterTable +ALTER TABLE "Link" ADD COLUMN "color" TEXT, +ADD COLUMN "icon" TEXT, +ADD COLUMN "iconWeight" TEXT; diff --git a/prisma/migrations/20240819005010_remove_collection_model_default_color/migration.sql b/prisma/migrations/20240819005010_remove_collection_model_default_color/migration.sql new file mode 100644 index 0000000..199e104 --- /dev/null +++ b/prisma/migrations/20240819005010_remove_collection_model_default_color/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "Collection" ALTER COLUMN "color" DROP NOT NULL, +ALTER COLUMN "color" DROP DEFAULT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 71b5b10..664dec5 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -94,7 +94,9 @@ model Collection { id Int @id @default(autoincrement()) name String description String @default("") - color String @default("#0ea5e9") + icon String? + iconWeight String? + color String? parentId Int? parent Collection? @relation("SubCollections", fields: [parentId], references: [id]) subCollections Collection[] @relation("SubCollections") @@ -133,6 +135,9 @@ model Link { collection Collection @relation(fields: [collectionId], references: [id]) collectionId Int tags Tag[] + icon String? + iconWeight String? + color String? url String? textContent String? preview String? diff --git a/styles/globals.css b/styles/globals.css index 1f97b6e..022c160 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -36,6 +36,14 @@ scrollbar-width: none; } +.hide-color-picker { + opacity: 0; + display: block; + width: 32px; + height: 32px; + border: none; +} + .hyphens { hyphens: auto; }