format
This commit is contained in:
parent
4faf389a2b
commit
94be3a7448
|
@ -1,5 +1,8 @@
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { AccountSettings, CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
import {
|
||||||
|
AccountSettings,
|
||||||
|
CollectionIncludingMembersAndLinkCount,
|
||||||
|
} from "@/types/global";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import ProfilePhoto from "./ProfilePhoto";
|
import ProfilePhoto from "./ProfilePhoto";
|
||||||
import usePermissions from "@/hooks/usePermissions";
|
import usePermissions from "@/hooks/usePermissions";
|
||||||
|
@ -33,7 +36,9 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||||
|
|
||||||
const permissions = usePermissions(collection.id as number);
|
const permissions = usePermissions(collection.id as number);
|
||||||
|
|
||||||
const [collectionOwner, setCollectionOwner] = useState<Partial<AccountSettings>>({});
|
const [collectionOwner, setCollectionOwner] = useState<
|
||||||
|
Partial<AccountSettings>
|
||||||
|
>({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchOwner = async () => {
|
const fetchOwner = async () => {
|
||||||
|
@ -151,9 +156,11 @@ export default function CollectionCard({ collection, className }: Props) {
|
||||||
<Link
|
<Link
|
||||||
href={`/collections/${collection.id}`}
|
href={`/collections/${collection.id}`}
|
||||||
style={{
|
style={{
|
||||||
backgroundImage: `linear-gradient(45deg, ${collection.color}30 10%, ${settings.theme === "dark" ? "oklch(var(--b2))" : "oklch(var(--b2))"
|
backgroundImage: `linear-gradient(45deg, ${collection.color}30 10%, ${
|
||||||
} 50%, ${settings.theme === "dark" ? "oklch(var(--b2))" : "oklch(var(--b2))"
|
settings.theme === "dark" ? "oklch(var(--b2))" : "oklch(var(--b2))"
|
||||||
} 100%)`,
|
} 50%, ${
|
||||||
|
settings.theme === "dark" ? "oklch(var(--b2))" : "oklch(var(--b2))"
|
||||||
|
} 100%)`,
|
||||||
}}
|
}}
|
||||||
className="card card-compact shadow-md hover:shadow-none duration-200 border border-neutral-content"
|
className="card card-compact shadow-md hover:shadow-none duration-200 border border-neutral-content"
|
||||||
>
|
>
|
||||||
|
|
|
@ -231,10 +231,11 @@ const renderItem = (
|
||||||
return (
|
return (
|
||||||
<div ref={provided.innerRef} {...provided.draggableProps} className="mb-1">
|
<div ref={provided.innerRef} {...provided.draggableProps} className="mb-1">
|
||||||
<div
|
<div
|
||||||
className={`${currentPath === `/collections/${collection.id}`
|
className={`${
|
||||||
? "bg-primary/20 is-active"
|
currentPath === `/collections/${collection.id}`
|
||||||
: "hover:bg-neutral/20"
|
? "bg-primary/20 is-active"
|
||||||
} duration-100 flex gap-1 items-center pr-2 pl-1 rounded-md`}
|
: "hover:bg-neutral/20"
|
||||||
|
} duration-100 flex gap-1 items-center pr-2 pl-1 rounded-md`}
|
||||||
>
|
>
|
||||||
{Icon(item as ExtendedTreeItem, onExpand, onCollapse)}
|
{Icon(item as ExtendedTreeItem, onExpand, onCollapse)}
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,15 @@ import ClickAwayHandler from "./ClickAwayHandler";
|
||||||
|
|
||||||
type MenuItem =
|
type MenuItem =
|
||||||
| {
|
| {
|
||||||
name: string;
|
name: string;
|
||||||
onClick: MouseEventHandler;
|
onClick: MouseEventHandler;
|
||||||
href?: string;
|
href?: string;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
name: string;
|
name: string;
|
||||||
onClick?: MouseEventHandler;
|
onClick?: MouseEventHandler;
|
||||||
href: string;
|
href: string;
|
||||||
}
|
}
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -60,46 +60,50 @@ export default function Dropdown({
|
||||||
}
|
}
|
||||||
}, [points, dropdownHeight]);
|
}, [points, dropdownHeight]);
|
||||||
|
|
||||||
return !points || pos && (
|
return (
|
||||||
<ClickAwayHandler
|
!points ||
|
||||||
onMount={(e) => {
|
(pos && (
|
||||||
setDropdownHeight(e.height);
|
<ClickAwayHandler
|
||||||
setDropdownWidth(e.width);
|
onMount={(e) => {
|
||||||
}}
|
setDropdownHeight(e.height);
|
||||||
style={
|
setDropdownWidth(e.width);
|
||||||
points
|
}}
|
||||||
? {
|
style={
|
||||||
position: "fixed",
|
points
|
||||||
top: `${pos?.y}px`,
|
? {
|
||||||
left: `${pos?.x}px`,
|
position: "fixed",
|
||||||
}
|
top: `${pos?.y}px`,
|
||||||
: undefined
|
left: `${pos?.x}px`,
|
||||||
}
|
}
|
||||||
onClickOutside={onClickOutside}
|
: undefined
|
||||||
className={`${className || ""
|
}
|
||||||
|
onClickOutside={onClickOutside}
|
||||||
|
className={`${
|
||||||
|
className || ""
|
||||||
} py-1 shadow-md border border-neutral-content bg-base-200 rounded-md flex flex-col z-20`}
|
} py-1 shadow-md border border-neutral-content bg-base-200 rounded-md flex flex-col z-20`}
|
||||||
>
|
>
|
||||||
{items.map((e, i) => {
|
{items.map((e, i) => {
|
||||||
const inner = e && (
|
const inner = e && (
|
||||||
<div className="cursor-pointer rounded-md">
|
<div className="cursor-pointer rounded-md">
|
||||||
<div className="flex items-center gap-2 py-1 px-2 hover:bg-base-100 duration-100">
|
<div className="flex items-center gap-2 py-1 px-2 hover:bg-base-100 duration-100">
|
||||||
<p className="select-none">{e.name}</p>
|
<p className="select-none">{e.name}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
|
||||||
|
|
||||||
return e && e.href ? (
|
return e && e.href ? (
|
||||||
<Link key={i} href={e.href}>
|
<Link key={i} href={e.href}>
|
||||||
{inner}
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
e && (
|
|
||||||
<div key={i} onClick={e.onClick}>
|
|
||||||
{inner}
|
{inner}
|
||||||
</div>
|
</Link>
|
||||||
)
|
) : (
|
||||||
);
|
e && (
|
||||||
})}
|
<div key={i} onClick={e.onClick}>
|
||||||
</ClickAwayHandler>
|
{inner}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ClickAwayHandler>
|
||||||
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,11 @@ type Props = {
|
||||||
onChange: (newValue: unknown, actionMeta: ActionMeta<unknown>) => void;
|
onChange: (newValue: unknown, actionMeta: ActionMeta<unknown>) => void;
|
||||||
showDefaultValue?: boolean;
|
showDefaultValue?: boolean;
|
||||||
defaultValue?:
|
defaultValue?:
|
||||||
| {
|
| {
|
||||||
label: string;
|
label: string;
|
||||||
value?: number;
|
value?: number;
|
||||||
}
|
}
|
||||||
| undefined;
|
| undefined;
|
||||||
creatable?: boolean;
|
creatable?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ export default function CollectionSelection({
|
||||||
components={{
|
components={{
|
||||||
Option: customOption,
|
Option: customOption,
|
||||||
}}
|
}}
|
||||||
// menuPosition="fixed"
|
// menuPosition="fixed"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -123,7 +123,7 @@ export default function CollectionSelection({
|
||||||
components={{
|
components={{
|
||||||
Option: customOption,
|
Option: customOption,
|
||||||
}}
|
}}
|
||||||
// menuPosition="fixed"
|
// menuPosition="fixed"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,8 +79,9 @@ export default function LinkActions({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={`dropdown dropdown-left absolute ${position || "top-3 right-3"
|
className={`dropdown dropdown-left absolute ${
|
||||||
} ${alignToTop ? "" : "dropdown-end"} z-20`}
|
position || "top-3 right-3"
|
||||||
|
} ${alignToTop ? "" : "dropdown-end"} z-20`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
|
@ -91,8 +92,9 @@ export default function LinkActions({
|
||||||
<i title="More" className="bi-three-dots text-xl" />
|
<i title="More" className="bi-three-dots text-xl" />
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
className={`dropdown-content z-[20] menu shadow bg-base-200 border border-neutral-content rounded-box w-44 mr-1 ${alignToTop ? "" : "translate-y-10"
|
className={`dropdown-content z-[20] menu shadow bg-base-200 border border-neutral-content rounded-box w-44 mr-1 ${
|
||||||
}`}
|
alignToTop ? "" : "translate-y-10"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<li>
|
<li>
|
||||||
<div
|
<div
|
||||||
|
@ -122,20 +124,21 @@ export default function LinkActions({
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
{permissions === true || permissions?.canUpdate && (
|
{permissions === true ||
|
||||||
<li>
|
(permissions?.canUpdate && (
|
||||||
<div
|
<li>
|
||||||
role="button"
|
<div
|
||||||
tabIndex={0}
|
role="button"
|
||||||
onClick={() => {
|
tabIndex={0}
|
||||||
(document?.activeElement as HTMLElement)?.blur();
|
onClick={() => {
|
||||||
setEditLinkModal(true);
|
(document?.activeElement as HTMLElement)?.blur();
|
||||||
}}
|
setEditLinkModal(true);
|
||||||
>
|
}}
|
||||||
{t("edit_link")}
|
>
|
||||||
</div>
|
{t("edit_link")}
|
||||||
</li>
|
</div>
|
||||||
)}
|
</li>
|
||||||
|
))}
|
||||||
{link.type === "url" && (
|
{link.type === "url" && (
|
||||||
<li>
|
<li>
|
||||||
<div
|
<div
|
||||||
|
@ -150,20 +153,21 @@ export default function LinkActions({
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
{permissions === true || permissions?.canDelete && (
|
{permissions === true ||
|
||||||
<li>
|
(permissions?.canDelete && (
|
||||||
<div
|
<li>
|
||||||
role="button"
|
<div
|
||||||
tabIndex={0}
|
role="button"
|
||||||
onClick={(e) => {
|
tabIndex={0}
|
||||||
(document?.activeElement as HTMLElement)?.blur();
|
onClick={(e) => {
|
||||||
e.shiftKey ? deleteLink() : setDeleteLinkModal(true);
|
(document?.activeElement as HTMLElement)?.blur();
|
||||||
}}
|
e.shiftKey ? deleteLink() : setDeleteLinkModal(true);
|
||||||
>
|
}}
|
||||||
{t("delete")}
|
>
|
||||||
</div>
|
{t("delete")}
|
||||||
</li>
|
</div>
|
||||||
)}
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -91,8 +91,9 @@ export default function LinkCardCompact({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={`${selectedStyle} border relative items-center flex ${!showInfo && !isPWA() ? "hover:bg-base-300 p-3" : "py-3"
|
className={`${selectedStyle} border relative items-center flex ${
|
||||||
} duration-200 rounded-lg w-full`}
|
!showInfo && !isPWA() ? "hover:bg-base-300 p-3" : "py-3"
|
||||||
|
} duration-200 rounded-lg w-full`}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
selectable
|
selectable
|
||||||
? handleCheckboxClick(link)
|
? handleCheckboxClick(link)
|
||||||
|
@ -152,8 +153,8 @@ export default function LinkCardCompact({
|
||||||
collection={collection}
|
collection={collection}
|
||||||
position="top-3 right-3"
|
position="top-3 right-3"
|
||||||
flipDropdown={flipDropdown}
|
flipDropdown={flipDropdown}
|
||||||
// toggleShowInfo={() => setShowInfo(!showInfo)}
|
// toggleShowInfo={() => setShowInfo(!showInfo)}
|
||||||
// linkInfo={showInfo}
|
// linkInfo={showInfo}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { useTranslation } from "next-i18next";
|
||||||
|
|
||||||
type Props = {};
|
type Props = {};
|
||||||
|
|
||||||
export default function MobileNavigation({ }: Props) {
|
export default function MobileNavigation({}: Props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [newLinkModal, setNewLinkModal] = useState(false);
|
const [newLinkModal, setNewLinkModal] = useState(false);
|
||||||
const [newCollectionModal, setNewCollectionModal] = useState(false);
|
const [newCollectionModal, setNewCollectionModal] = useState(false);
|
||||||
|
@ -21,8 +21,9 @@ export default function MobileNavigation({ }: Props) {
|
||||||
className={`fixed bottom-0 left-0 right-0 z-30 duration-200 sm:hidden`}
|
className={`fixed bottom-0 left-0 right-0 z-30 duration-200 sm:hidden`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`w-full flex bg-base-100 ${isIphone() && isPWA() ? "pb-5" : ""
|
className={`w-full flex bg-base-100 ${
|
||||||
} border-solid border-t-neutral-content border-t`}
|
isIphone() && isPWA() ? "pb-5" : ""
|
||||||
|
} border-solid border-t-neutral-content border-t`}
|
||||||
>
|
>
|
||||||
<MobileNavigationButton href={`/dashboard`} icon={"bi-house"} />
|
<MobileNavigationButton href={`/dashboard`} icon={"bi-house"} />
|
||||||
<MobileNavigationButton
|
<MobileNavigationButton
|
||||||
|
@ -83,9 +84,7 @@ export default function MobileNavigation({ }: Props) {
|
||||||
<MobileNavigationButton href={`/collections`} icon={"bi-folder"} />
|
<MobileNavigationButton href={`/collections`} icon={"bi-folder"} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{newLinkModal && (
|
{newLinkModal && <NewLinkModal onClose={() => setNewLinkModal(false)} />}
|
||||||
<NewLinkModal onClose={() => setNewLinkModal(false)} />
|
|
||||||
)}
|
|
||||||
{newCollectionModal && (
|
{newCollectionModal && (
|
||||||
<NewCollectionModal onClose={() => setNewCollectionModal(false)} />
|
<NewCollectionModal onClose={() => setNewCollectionModal(false)} />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -2,7 +2,11 @@ import React, { useEffect, useState } from "react";
|
||||||
import TextInput from "@/components/TextInput";
|
import TextInput from "@/components/TextInput";
|
||||||
import useCollectionStore from "@/store/collections";
|
import useCollectionStore from "@/store/collections";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { AccountSettings, CollectionIncludingMembersAndLinkCount, Member } from "@/types/global";
|
import {
|
||||||
|
AccountSettings,
|
||||||
|
CollectionIncludingMembersAndLinkCount,
|
||||||
|
Member,
|
||||||
|
} from "@/types/global";
|
||||||
import getPublicUserData from "@/lib/client/getPublicUserData";
|
import getPublicUserData from "@/lib/client/getPublicUserData";
|
||||||
import useAccountStore from "@/store/account";
|
import useAccountStore from "@/store/account";
|
||||||
import usePermissions from "@/hooks/usePermissions";
|
import usePermissions from "@/hooks/usePermissions";
|
||||||
|
@ -62,7 +66,9 @@ export default function EditCollectionSharingModal({
|
||||||
|
|
||||||
const [memberUsername, setMemberUsername] = useState("");
|
const [memberUsername, setMemberUsername] = useState("");
|
||||||
|
|
||||||
const [collectionOwner, setCollectionOwner] = useState<Partial<AccountSettings>>({});
|
const [collectionOwner, setCollectionOwner] = useState<
|
||||||
|
Partial<AccountSettings>
|
||||||
|
>({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchOwner = async () => {
|
const fetchOwner = async () => {
|
||||||
|
|
|
@ -38,7 +38,9 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
|
||||||
|
|
||||||
let isPublic = router.pathname.startsWith("/public") ? true : undefined;
|
let isPublic = router.pathname.startsWith("/public") ? true : undefined;
|
||||||
|
|
||||||
const [collectionOwner, setCollectionOwner] = useState<Partial<AccountSettings>>({});
|
const [collectionOwner, setCollectionOwner] = useState<
|
||||||
|
Partial<AccountSettings>
|
||||||
|
>({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchOwner = async () => {
|
const fetchOwner = async () => {
|
||||||
|
@ -143,9 +145,9 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
|
||||||
<p className="text-xl font-thin">{t("preserved_formats")}</p>
|
<p className="text-xl font-thin">{t("preserved_formats")}</p>
|
||||||
<div className="divider mb-2 mt-1"></div>
|
<div className="divider mb-2 mt-1"></div>
|
||||||
{screenshotAvailable(link) ||
|
{screenshotAvailable(link) ||
|
||||||
pdfAvailable(link) ||
|
pdfAvailable(link) ||
|
||||||
readabilityAvailable(link) ||
|
readabilityAvailable(link) ||
|
||||||
monolithAvailable(link) ? (
|
monolithAvailable(link) ? (
|
||||||
<p className="mb-3">{t("available_formats")}</p>
|
<p className="mb-3">{t("available_formats")}</p>
|
||||||
) : (
|
) : (
|
||||||
""
|
""
|
||||||
|
@ -206,21 +208,25 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
|
||||||
<p className="text-center text-2xl">{t("preservation_in_queue")}</p>
|
<p className="text-center text-2xl">{t("preservation_in_queue")}</p>
|
||||||
<p className="text-center text-lg">{t("check_back_later")}</p>
|
<p className="text-center text-lg">{t("check_back_later")}</p>
|
||||||
</div>
|
</div>
|
||||||
) : !isReady() && atLeastOneFormatAvailable() && (
|
) : (
|
||||||
<div className={`w-full h-full flex flex-col justify-center p-5`}>
|
!isReady() &&
|
||||||
<BeatLoader
|
atLeastOneFormatAvailable() && (
|
||||||
color="oklch(var(--p))"
|
<div className={`w-full h-full flex flex-col justify-center p-5`}>
|
||||||
className="mx-auto mb-3"
|
<BeatLoader
|
||||||
size={20}
|
color="oklch(var(--p))"
|
||||||
/>
|
className="mx-auto mb-3"
|
||||||
<p className="text-center">{t("there_are_more_formats")}</p>
|
size={20}
|
||||||
<p className="text-center text-sm">{t("check_back_later")}</p>
|
/>
|
||||||
</div>
|
<p className="text-center">{t("there_are_more_formats")}</p>
|
||||||
|
<p className="text-center text-sm">{t("check_back_later")}</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`flex flex-col sm:flex-row gap-3 items-center justify-center ${isReady() ? "sm:mt " : ""
|
className={`flex flex-col sm:flex-row gap-3 items-center justify-center ${
|
||||||
}`}
|
isReady() ? "sm:mt " : ""
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={`https://web.archive.org/web/${link?.url?.replace(
|
href={`https://web.archive.org/web/${link?.url?.replace(
|
||||||
|
|
|
@ -120,9 +120,7 @@ export default function Navbar() {
|
||||||
</ClickAwayHandler>
|
</ClickAwayHandler>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{newLinkModal && (
|
{newLinkModal && <NewLinkModal onClose={() => setNewLinkModal(false)} />}
|
||||||
<NewLinkModal onClose={() => setNewLinkModal(false)} />
|
|
||||||
)}
|
|
||||||
{newCollectionModal && (
|
{newCollectionModal && (
|
||||||
<NewCollectionModal onClose={() => setNewCollectionModal(false)} />
|
<NewCollectionModal onClose={() => setNewCollectionModal(false)} />
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -39,9 +39,7 @@ export default function NoLinksFound({ text }: Props) {
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{newLinkModal && (
|
{newLinkModal && <NewLinkModal onClose={() => setNewLinkModal(false)} />}
|
||||||
<NewLinkModal onClose={() => setNewLinkModal(false)} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,18 +90,20 @@ export default function PreservedFormatRow({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
{downloadable || false && (
|
{downloadable ||
|
||||||
<div
|
(false && (
|
||||||
onClick={() => handleDownload()}
|
<div
|
||||||
className="btn btn-sm btn-square"
|
onClick={() => handleDownload()}
|
||||||
>
|
className="btn btn-sm btn-square"
|
||||||
<i className="bi-cloud-arrow-down text-xl text-neutral" />
|
>
|
||||||
</div>
|
<i className="bi-cloud-arrow-down text-xl text-neutral" />
|
||||||
)}
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
href={`${isPublic ? "/public" : ""
|
href={`${
|
||||||
}/preserved/${link?.id}?format=${format}`}
|
isPublic ? "/public" : ""
|
||||||
|
}/preserved/${link?.id}?format=${format}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="btn btn-sm btn-square"
|
className="btn btn-sm btn-square"
|
||||||
>
|
>
|
||||||
|
|
|
@ -32,8 +32,9 @@ export default function ProfileDropdown() {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
className={`dropdown-content z-[1] menu shadow bg-base-200 border border-neutral-content rounded-box ${isAdmin ? "w-48" : "w-40"
|
className={`dropdown-content z-[1] menu shadow bg-base-200 border border-neutral-content rounded-box ${
|
||||||
} mt-1`}
|
isAdmin ? "w-48" : "w-40"
|
||||||
|
} mt-1`}
|
||||||
>
|
>
|
||||||
<li>
|
<li>
|
||||||
<Link
|
<Link
|
||||||
|
|
|
@ -192,7 +192,8 @@ export default function ReadableView({ link }: Props) {
|
||||||
>
|
>
|
||||||
<i className="bi-link-45deg"></i>
|
<i className="bi-link-45deg"></i>
|
||||||
|
|
||||||
{isValidUrl(link?.url || "") && new URL(link?.url as string).host}
|
{isValidUrl(link?.url || "") &&
|
||||||
|
new URL(link?.url as string).host}
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -229,10 +230,10 @@ export default function ReadableView({ link }: Props) {
|
||||||
<p className="min-w-fit text-sm text-neutral">
|
<p className="min-w-fit text-sm text-neutral">
|
||||||
{date
|
{date
|
||||||
? new Date(date).toLocaleString("en-US", {
|
? new Date(date).toLocaleString("en-US", {
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
month: "long",
|
month: "long",
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
})
|
})
|
||||||
: undefined}
|
: undefined}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -257,8 +258,9 @@ export default function ReadableView({ link }: Props) {
|
||||||
></div>
|
></div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
className={`w-full h-full flex flex-col justify-center p-10 ${link?.readable === "pending" || !link?.readable ? "skeleton" : ""
|
className={`w-full h-full flex flex-col justify-center p-10 ${
|
||||||
}`}
|
link?.readable === "pending" || !link?.readable ? "skeleton" : ""
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
|
|
@ -10,7 +10,9 @@ export default function ToggleDarkMode({ className }: Props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { settings, updateSettings } = useLocalSettingsStore();
|
const { settings, updateSettings } = useLocalSettingsStore();
|
||||||
|
|
||||||
const [theme, setTheme] = useState<string | null>(localStorage.getItem("theme"));
|
const [theme, setTheme] = useState<string | null>(
|
||||||
|
localStorage.getItem("theme")
|
||||||
|
);
|
||||||
|
|
||||||
const handleToggle = (e: ChangeEvent<HTMLInputElement>) => {
|
const handleToggle = (e: ChangeEvent<HTMLInputElement>) => {
|
||||||
setTheme(e.target.checked ? "dark" : "light");
|
setTheme(e.target.checked ? "dark" : "light");
|
||||||
|
|
|
@ -25,8 +25,9 @@ export default function CenteredForm({
|
||||||
<div className="m-auto flex flex-col gap-2 w-full">
|
<div className="m-auto flex flex-col gap-2 w-full">
|
||||||
{settings.theme && (
|
{settings.theme && (
|
||||||
<Image
|
<Image
|
||||||
src={`/linkwarden_${settings.theme === "dark" ? "dark" : "light"
|
src={`/linkwarden_${
|
||||||
}.png`}
|
settings.theme === "dark" ? "dark" : "light"
|
||||||
|
}.png`}
|
||||||
width={640}
|
width={640}
|
||||||
height={136}
|
height={136}
|
||||||
alt="Linkwarden"
|
alt="Linkwarden"
|
||||||
|
|
|
@ -3,15 +3,15 @@ import { LinkRequestQuery, Order, Sort } from "@/types/global";
|
||||||
|
|
||||||
type Response<D> =
|
type Response<D> =
|
||||||
| {
|
| {
|
||||||
data: D;
|
data: D;
|
||||||
message: string;
|
message: string;
|
||||||
status: number;
|
status: number;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
data: D;
|
data: D;
|
||||||
message: string;
|
message: string;
|
||||||
status: number;
|
status: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function getDashboardData(
|
export default async function getDashboardData(
|
||||||
userId: number,
|
userId: number,
|
||||||
|
|
|
@ -26,7 +26,7 @@ export default async function exportData(userId: number) {
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
data.forEach((item) => redactIds(item));
|
data.forEach((item) => redactIds(item));
|
||||||
} else if (data !== null && typeof data === "object") {
|
} else if (data !== null && typeof data === "object") {
|
||||||
const fieldsToRedact = ['id', 'parentId', 'collectionId', 'ownerId'];
|
const fieldsToRedact = ["id", "parentId", "collectionId", "ownerId"];
|
||||||
|
|
||||||
fieldsToRedact.forEach((field) => {
|
fieldsToRedact.forEach((field) => {
|
||||||
if (field in data) {
|
if (field in data) {
|
||||||
|
@ -37,7 +37,10 @@ export default async function exportData(userId: number) {
|
||||||
// Recursively call redactIds for each property that is an object or an array
|
// Recursively call redactIds for each property that is an object or an array
|
||||||
Object.keys(data).forEach((key) => {
|
Object.keys(data).forEach((key) => {
|
||||||
const value = (data as any)[key];
|
const value = (data as any)[key];
|
||||||
if (value !== null && (typeof value === "object" || Array.isArray(value))) {
|
if (
|
||||||
|
value !== null &&
|
||||||
|
(typeof value === "object" || Array.isArray(value))
|
||||||
|
) {
|
||||||
redactIds(value);
|
redactIds(value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -63,7 +63,8 @@ async function processBookmarks(
|
||||||
) as Element;
|
) as Element;
|
||||||
|
|
||||||
if (collectionName) {
|
if (collectionName) {
|
||||||
const collectionNameContent = (collectionName.children[0] as TextNode)?.content;
|
const collectionNameContent = (collectionName.children[0] as TextNode)
|
||||||
|
?.content;
|
||||||
if (collectionNameContent) {
|
if (collectionNameContent) {
|
||||||
collectionId = await createCollection(
|
collectionId = await createCollection(
|
||||||
userId,
|
userId,
|
||||||
|
@ -274,4 +275,3 @@ function processNodes(nodes: Node[]) {
|
||||||
nodes.forEach(findAndProcessDL);
|
nodes.forEach(findAndProcessDL);
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,23 +84,23 @@ export default async function importFromWallabag(
|
||||||
tags:
|
tags:
|
||||||
link.tags && link.tags[0]
|
link.tags && link.tags[0]
|
||||||
? {
|
? {
|
||||||
connectOrCreate: link.tags.map((tag) => ({
|
connectOrCreate: link.tags.map((tag) => ({
|
||||||
where: {
|
where: {
|
||||||
name_ownerId: {
|
name_ownerId: {
|
||||||
name: tag.trim(),
|
name: tag.trim(),
|
||||||
ownerId: userId,
|
ownerId: userId,
|
||||||
},
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
name: tag.trim(),
|
|
||||||
owner: {
|
|
||||||
connect: {
|
|
||||||
id: userId,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
create: {
|
||||||
})),
|
name: tag.trim(),
|
||||||
}
|
owner: {
|
||||||
|
connect: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,10 +24,7 @@ export default async function deleteUserById(
|
||||||
|
|
||||||
if (!isServerAdmin) {
|
if (!isServerAdmin) {
|
||||||
if (user.password) {
|
if (user.password) {
|
||||||
const isPasswordValid = bcrypt.compareSync(
|
const isPasswordValid = bcrypt.compareSync(body.password, user.password);
|
||||||
body.password,
|
|
||||||
user.password
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!isPasswordValid && !isServerAdmin) {
|
if (!isPasswordValid && !isServerAdmin) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -28,10 +28,10 @@ export default async function readFile(filePath: string) {
|
||||||
try {
|
try {
|
||||||
let returnObject:
|
let returnObject:
|
||||||
| {
|
| {
|
||||||
file: Buffer | string;
|
file: Buffer | string;
|
||||||
contentType: ReturnContentTypes;
|
contentType: ReturnContentTypes;
|
||||||
status: number;
|
status: number;
|
||||||
}
|
}
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
const headObjectAsync = util.promisify(
|
const headObjectAsync = util.promisify(
|
||||||
|
|
|
@ -7,10 +7,15 @@ export function isPWA() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isIphone() {
|
export function isIphone() {
|
||||||
return /iPhone/.test(navigator.userAgent) && !(window as unknown as { MSStream?: any }).MSStream;
|
return (
|
||||||
|
/iPhone/.test(navigator.userAgent) &&
|
||||||
|
!(window as unknown as { MSStream?: any }).MSStream
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function dropdownTriggerer(e: React.FocusEvent<HTMLElement> | React.MouseEvent<HTMLElement>) {
|
export function dropdownTriggerer(
|
||||||
|
e: React.FocusEvent<HTMLElement> | React.MouseEvent<HTMLElement>
|
||||||
|
) {
|
||||||
let targetEl = e.currentTarget;
|
let targetEl = e.currentTarget;
|
||||||
if (targetEl && targetEl.matches(":focus")) {
|
if (targetEl && targetEl.matches(":focus")) {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
|
|
|
@ -39,7 +39,9 @@ export function monolithAvailable(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function previewAvailable(link: LinkIncludingShortenedCollectionAndTags) {
|
export function previewAvailable(
|
||||||
|
link: LinkIncludingShortenedCollectionAndTags
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
link &&
|
link &&
|
||||||
link.preview &&
|
link.preview &&
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
i18n: {
|
i18n: {
|
||||||
defaultLocale: "en",
|
defaultLocale: "en",
|
||||||
locales: ["en","it"],
|
locales: ["en", "it"],
|
||||||
},
|
},
|
||||||
reloadOnPrerender: process.env.NODE_ENV === "development",
|
reloadOnPrerender: process.env.NODE_ENV === "development",
|
||||||
};
|
};
|
||||||
|
|
|
@ -104,9 +104,7 @@ export default function Admin() {
|
||||||
<p>{t("no_users_found")}</p>
|
<p>{t("no_users_found")}</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{newUserModal && (
|
{newUserModal && <NewUserModal onClose={() => setNewUserModal(false)} />}
|
||||||
<NewUserModal onClose={() => setNewUserModal(false)} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -189,8 +189,12 @@ export default async function Index(req: NextApiRequest, res: NextApiResponse) {
|
||||||
where: { id: linkId },
|
where: { id: linkId },
|
||||||
data: {
|
data: {
|
||||||
preview: isPDF ? "unavailable" : undefined,
|
preview: isPDF ? "unavailable" : undefined,
|
||||||
image: isImage ? `archives/${collectionPermissions.id}/${linkId + suffix}` : null,
|
image: isImage
|
||||||
pdf: isPDF ? `archives/${collectionPermissions.id}/${linkId + suffix}` : null,
|
? `archives/${collectionPermissions.id}/${linkId + suffix}`
|
||||||
|
: null,
|
||||||
|
pdf: isPDF
|
||||||
|
? `archives/${collectionPermissions.id}/${linkId + suffix}`
|
||||||
|
: null,
|
||||||
lastPreserved: new Date().toISOString(),
|
lastPreserved: new Date().toISOString(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -54,7 +54,9 @@ export default function Index() {
|
||||||
|
|
||||||
const { account } = useAccountStore();
|
const { account } = useAccountStore();
|
||||||
|
|
||||||
const [collectionOwner, setCollectionOwner] = useState<Partial<AccountSettings>>({});
|
const [collectionOwner, setCollectionOwner] = useState<
|
||||||
|
Partial<AccountSettings>
|
||||||
|
>({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchOwner = async () => {
|
const fetchOwner = async () => {
|
||||||
|
@ -108,8 +110,9 @@ export default function Index() {
|
||||||
<div
|
<div
|
||||||
className="h-[60rem] p-5 flex gap-3 flex-col"
|
className="h-[60rem] p-5 flex gap-3 flex-col"
|
||||||
style={{
|
style={{
|
||||||
backgroundImage: `linear-gradient(${activeCollection?.color}20 10%, ${settings.theme === "dark" ? "#262626" : "#f3f4f6"
|
backgroundImage: `linear-gradient(${activeCollection?.color}20 10%, ${
|
||||||
} 13rem, ${settings.theme === "dark" ? "#171717" : "#ffffff"} 100%)`,
|
settings.theme === "dark" ? "#262626" : "#f3f4f6"
|
||||||
|
} 13rem, ${settings.theme === "dark" ? "#171717" : "#ffffff"} 100%)`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{activeCollection && (
|
{activeCollection && (
|
||||||
|
@ -210,7 +213,7 @@ export default function Index() {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{activeCollection.members
|
{activeCollection.members
|
||||||
.sort((a, b) => (a.userId) - (b.userId))
|
.sort((a, b) => a.userId - b.userId)
|
||||||
.map((e, i) => {
|
.map((e, i) => {
|
||||||
return (
|
return (
|
||||||
<ProfilePhoto
|
<ProfilePhoto
|
||||||
|
@ -233,20 +236,20 @@ export default function Index() {
|
||||||
|
|
||||||
<p className="text-neutral text-sm">
|
<p className="text-neutral text-sm">
|
||||||
{activeCollection.members.length > 0 &&
|
{activeCollection.members.length > 0 &&
|
||||||
activeCollection.members.length === 1
|
activeCollection.members.length === 1
|
||||||
? t("by_author_and_other", {
|
? t("by_author_and_other", {
|
||||||
author: collectionOwner.name,
|
|
||||||
count: activeCollection.members.length,
|
|
||||||
})
|
|
||||||
: activeCollection.members.length > 0 &&
|
|
||||||
activeCollection.members.length !== 1
|
|
||||||
? t("by_author_and_others", {
|
|
||||||
author: collectionOwner.name,
|
author: collectionOwner.name,
|
||||||
count: activeCollection.members.length,
|
count: activeCollection.members.length,
|
||||||
})
|
})
|
||||||
|
: activeCollection.members.length > 0 &&
|
||||||
|
activeCollection.members.length !== 1
|
||||||
|
? t("by_author_and_others", {
|
||||||
|
author: collectionOwner.name,
|
||||||
|
count: activeCollection.members.length,
|
||||||
|
})
|
||||||
: t("by_author", {
|
: t("by_author", {
|
||||||
author: collectionOwner.name,
|
author: collectionOwner.name,
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -291,15 +294,15 @@ export default function Index() {
|
||||||
setSortBy={setSortBy}
|
setSortBy={setSortBy}
|
||||||
editMode={
|
editMode={
|
||||||
permissions === true ||
|
permissions === true ||
|
||||||
permissions?.canUpdate ||
|
permissions?.canUpdate ||
|
||||||
permissions?.canDelete
|
permissions?.canDelete
|
||||||
? editMode
|
? editMode
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
setEditMode={
|
setEditMode={
|
||||||
permissions === true ||
|
permissions === true ||
|
||||||
permissions?.canUpdate ||
|
permissions?.canUpdate ||
|
||||||
permissions?.canDelete
|
permissions?.canDelete
|
||||||
? setEditMode
|
? setEditMode
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
|
@ -307,11 +310,11 @@ export default function Index() {
|
||||||
<p>
|
<p>
|
||||||
{activeCollection?._count?.links === 1
|
{activeCollection?._count?.links === 1
|
||||||
? t("showing_count_result", {
|
? t("showing_count_result", {
|
||||||
count: activeCollection?._count?.links,
|
count: activeCollection?._count?.links,
|
||||||
})
|
})
|
||||||
: t("showing_count_results", {
|
: t("showing_count_results", {
|
||||||
count: activeCollection?._count?.links,
|
count: activeCollection?._count?.links,
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
</LinkListOptions>
|
</LinkListOptions>
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,10 @@ export default function Dashboard() {
|
||||||
handleNumberOfLinksToShow();
|
handleNumberOfLinksToShow();
|
||||||
}, [width]);
|
}, [width]);
|
||||||
|
|
||||||
const importBookmarks = async (e: React.ChangeEvent<HTMLInputElement>, format: MigrationFormat) => {
|
const importBookmarks = async (
|
||||||
|
e: React.ChangeEvent<HTMLInputElement>,
|
||||||
|
format: MigrationFormat
|
||||||
|
) => {
|
||||||
const file: File | null = e.target.files && e.target.files[0];
|
const file: File | null = e.target.files && e.target.files[0];
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
|
@ -324,9 +327,7 @@ export default function Dashboard() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{newLinkModal && (
|
{newLinkModal && <NewLinkModal onClose={() => setNewLinkModal(false)} />}
|
||||||
<NewLinkModal onClose={() => setNewLinkModal(false)} />
|
|
||||||
)}
|
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,9 +224,9 @@ export default function Login({
|
||||||
loading={submitLoader}
|
loading={submitLoader}
|
||||||
>
|
>
|
||||||
{value.name.toLowerCase() === "google" ||
|
{value.name.toLowerCase() === "google" ||
|
||||||
value.name.toLowerCase() === "apple" && (
|
(value.name.toLowerCase() === "apple" && (
|
||||||
<i className={"bi-" + value.name.toLowerCase()}></i>
|
<i className={"bi-" + value.name.toLowerCase()}></i>
|
||||||
)}
|
))}
|
||||||
{value.name}
|
{value.name}
|
||||||
</Button>
|
</Button>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
@ -37,7 +37,9 @@ export default function PublicCollections() {
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const [collectionOwner, setCollectionOwner] = useState<Partial<AccountSettings>>({});
|
const [collectionOwner, setCollectionOwner] = useState<
|
||||||
|
Partial<AccountSettings>
|
||||||
|
>({});
|
||||||
|
|
||||||
const [searchFilter, setSearchFilter] = useState({
|
const [searchFilter, setSearchFilter] = useState({
|
||||||
name: true,
|
name: true,
|
||||||
|
@ -103,8 +105,9 @@ export default function PublicCollections() {
|
||||||
<div
|
<div
|
||||||
className="h-96"
|
className="h-96"
|
||||||
style={{
|
style={{
|
||||||
backgroundImage: `linear-gradient(${collection?.color}30 10%, ${settings.theme === "dark" ? "#262626" : "#f3f4f6"
|
backgroundImage: `linear-gradient(${collection?.color}30 10%, ${
|
||||||
} 13rem, ${settings.theme === "dark" ? "#171717" : "#ffffff"} 100%)`,
|
settings.theme === "dark" ? "#262626" : "#f3f4f6"
|
||||||
|
} 13rem, ${settings.theme === "dark" ? "#171717" : "#ffffff"} 100%)`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{collection && (
|
{collection && (
|
||||||
|
@ -175,20 +178,20 @@ export default function PublicCollections() {
|
||||||
|
|
||||||
<p className="text-neutral text-sm">
|
<p className="text-neutral text-sm">
|
||||||
{collection.members.length > 0 &&
|
{collection.members.length > 0 &&
|
||||||
collection.members.length === 1
|
collection.members.length === 1
|
||||||
? t("by_author_and_other", {
|
? t("by_author_and_other", {
|
||||||
author: collectionOwner.name,
|
|
||||||
count: collection.members.length,
|
|
||||||
})
|
|
||||||
: collection.members.length > 0 &&
|
|
||||||
collection.members.length !== 1
|
|
||||||
? t("by_author_and_others", {
|
|
||||||
author: collectionOwner.name,
|
author: collectionOwner.name,
|
||||||
count: collection.members.length,
|
count: collection.members.length,
|
||||||
})
|
})
|
||||||
|
: collection.members.length > 0 &&
|
||||||
|
collection.members.length !== 1
|
||||||
|
? t("by_author_and_others", {
|
||||||
|
author: collectionOwner.name,
|
||||||
|
count: collection.members.length,
|
||||||
|
})
|
||||||
: t("by_author", {
|
: t("by_author", {
|
||||||
author: collectionOwner.name,
|
author: collectionOwner.name,
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -212,11 +215,11 @@ export default function PublicCollections() {
|
||||||
placeholder={
|
placeholder={
|
||||||
collection._count?.links === 1
|
collection._count?.links === 1
|
||||||
? t("search_count_link", {
|
? t("search_count_link", {
|
||||||
count: collection._count?.links,
|
count: collection._count?.links,
|
||||||
})
|
})
|
||||||
: t("search_count_links", {
|
: t("search_count_links", {
|
||||||
count: collection._count?.links,
|
count: collection._count?.links,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</LinkListOptions>
|
</LinkListOptions>
|
||||||
|
|
|
@ -133,9 +133,9 @@ export default function Register({
|
||||||
loading={submitLoader}
|
loading={submitLoader}
|
||||||
>
|
>
|
||||||
{value.name.toLowerCase() === "google" ||
|
{value.name.toLowerCase() === "google" ||
|
||||||
value.name.toLowerCase() === "apple" && (
|
(value.name.toLowerCase() === "apple" && (
|
||||||
<i className={"bi-" + value.name.toLowerCase()}></i>
|
<i className={"bi-" + value.name.toLowerCase()}></i>
|
||||||
)}
|
))}
|
||||||
{value.name}
|
{value.name}
|
||||||
</Button>
|
</Button>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
@ -149,8 +149,8 @@ export default function Register({
|
||||||
text={
|
text={
|
||||||
process.env.NEXT_PUBLIC_STRIPE
|
process.env.NEXT_PUBLIC_STRIPE
|
||||||
? t("trial_offer_desc", {
|
? t("trial_offer_desc", {
|
||||||
count: Number(process.env.NEXT_PUBLIC_TRIAL_PERIOD_DAYS || 14),
|
count: Number(process.env.NEXT_PUBLIC_TRIAL_PERIOD_DAYS || 14),
|
||||||
})
|
})
|
||||||
: t("register_desc")
|
: t("register_desc")
|
||||||
}
|
}
|
||||||
data-testid="registration-form"
|
data-testid="registration-form"
|
||||||
|
|
|
@ -29,19 +29,19 @@ export default function Account() {
|
||||||
!objectIsEmpty(account)
|
!objectIsEmpty(account)
|
||||||
? account
|
? account
|
||||||
: ({
|
: ({
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
id: null,
|
id: null,
|
||||||
name: "",
|
name: "",
|
||||||
username: "",
|
username: "",
|
||||||
email: "",
|
email: "",
|
||||||
emailVerified: null,
|
emailVerified: null,
|
||||||
password: undefined,
|
password: undefined,
|
||||||
image: "",
|
image: "",
|
||||||
isPrivate: true,
|
isPrivate: true,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
createdAt: null,
|
createdAt: null,
|
||||||
whitelistedUsers: [],
|
whitelistedUsers: [],
|
||||||
} as unknown as AccountSettings)
|
} as unknown as AccountSettings)
|
||||||
);
|
);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -102,7 +102,10 @@ export default function Account() {
|
||||||
setSubmitLoader(false);
|
setSubmitLoader(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const importBookmarks = async (e: ChangeEvent<HTMLInputElement>, format: MigrationFormat) => {
|
const importBookmarks = async (
|
||||||
|
e: ChangeEvent<HTMLInputElement>,
|
||||||
|
format: MigrationFormat
|
||||||
|
) => {
|
||||||
setSubmitLoader(true);
|
setSubmitLoader(true);
|
||||||
const file = e.target.files?.[0];
|
const file = e.target.files?.[0];
|
||||||
|
|
||||||
|
@ -421,7 +424,8 @@ export default function Account() {
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
{t("delete_account_warning")}
|
{t("delete_account_warning")}
|
||||||
{process.env.NEXT_PUBLIC_STRIPE && " " + t("cancel_subscription_notice")}
|
{process.env.NEXT_PUBLIC_STRIPE &&
|
||||||
|
" " + t("cancel_subscription_notice")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@ export enum Sort {
|
||||||
DescriptionZA,
|
DescriptionZA,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Order = { [key: string]: 'asc' | 'desc' };
|
export type Order = { [key: string]: "asc" | "desc" };
|
||||||
|
|
||||||
export type LinkRequestQuery = {
|
export type LinkRequestQuery = {
|
||||||
sort: Sort;
|
sort: Sort;
|
||||||
|
|
Ŝarĝante…
Reference in New Issue