Merge pull request #459 from IsaacWise06/issue/367
feat(links): Allow users to choose what happens when they click a link
This commit is contained in:
commit
aef55d65a1
|
@ -14,8 +14,8 @@ import Image from "next/image";
|
||||||
import { previewAvailable } from "@/lib/shared/getArchiveValidity";
|
import { previewAvailable } from "@/lib/shared/getArchiveValidity";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import LinkIcon from "./LinkComponents/LinkIcon";
|
import LinkIcon from "./LinkComponents/LinkIcon";
|
||||||
import LinkGroupedIconURL from "./LinkComponents/LinkGroupedIconURL";
|
|
||||||
import useOnScreen from "@/hooks/useOnScreen";
|
import useOnScreen from "@/hooks/useOnScreen";
|
||||||
|
import { generateLinkHref } from "@/lib/client/generateLinkHref";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
link: LinkIncludingShortenedCollectionAndTags;
|
link: LinkIncludingShortenedCollectionAndTags;
|
||||||
|
@ -26,8 +26,6 @@ type Props = {
|
||||||
|
|
||||||
export default function LinkGrid({
|
export default function LinkGrid({
|
||||||
link,
|
link,
|
||||||
count,
|
|
||||||
className,
|
|
||||||
flipDropdown,
|
flipDropdown,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { collections } = useCollectionStore();
|
const { collections } = useCollectionStore();
|
||||||
|
@ -88,7 +86,7 @@ export default function LinkGrid({
|
||||||
className="border border-solid border-neutral-content bg-base-200 shadow-md hover:shadow-none duration-100 rounded-2xl relative"
|
className="border border-solid border-neutral-content bg-base-200 shadow-md hover:shadow-none duration-100 rounded-2xl relative"
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={link.url || ""}
|
href={generateLinkHref(link)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="rounded-2xl cursor-pointer"
|
className="rounded-2xl cursor-pointer"
|
||||||
>
|
>
|
||||||
|
|
|
@ -18,7 +18,7 @@ type Props = {
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function LinkGrid({ link, count, className }: Props) {
|
export default function LinkGrid({ link }: Props) {
|
||||||
const { collections } = useCollectionStore();
|
const { collections } = useCollectionStore();
|
||||||
|
|
||||||
const { links } = useLinkStore();
|
const { links } = useLinkStore();
|
||||||
|
@ -101,7 +101,7 @@ export default function LinkGrid({ link, count, className }: Props) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<LinkActions
|
<LinkActions
|
||||||
toggleShowInfo={() => {}}
|
toggleShowInfo={() => { }}
|
||||||
linkInfo={false}
|
linkInfo={false}
|
||||||
link={link}
|
link={link}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import LinkCollection from "@/components/LinkViews/LinkComponents/LinkCollection
|
||||||
import LinkIcon from "@/components/LinkViews/LinkComponents/LinkIcon";
|
import LinkIcon from "@/components/LinkViews/LinkComponents/LinkIcon";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { isPWA } from "@/lib/client/utils";
|
import { isPWA } from "@/lib/client/utils";
|
||||||
|
import { generateLinkHref } from "@/lib/client/generateLinkHref";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
link: LinkIncludingShortenedCollectionAndTags;
|
link: LinkIncludingShortenedCollectionAndTags;
|
||||||
|
@ -22,12 +23,9 @@ type Props = {
|
||||||
|
|
||||||
export default function LinkCardCompact({
|
export default function LinkCardCompact({
|
||||||
link,
|
link,
|
||||||
count,
|
|
||||||
className,
|
|
||||||
flipDropdown,
|
flipDropdown,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { collections } = useCollectionStore();
|
const { collections } = useCollectionStore();
|
||||||
|
|
||||||
const { links } = useLinkStore();
|
const { links } = useLinkStore();
|
||||||
|
|
||||||
let shortendURL;
|
let shortendURL;
|
||||||
|
@ -58,12 +56,11 @@ export default function LinkCardCompact({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={`border-neutral-content relative ${
|
className={`border-neutral-content relative ${!showInfo && !isPWA() ? "hover:bg-base-300 p-3" : "py-3"
|
||||||
!showInfo && !isPWA() ? "hover:bg-base-300 p-3" : "py-3"
|
} duration-200 rounded-lg`}
|
||||||
} duration-200 rounded-lg`}
|
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={link.url || ""}
|
href={generateLinkHref(link)}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
className="flex items-start cursor-pointer"
|
className="flex items-start cursor-pointer"
|
||||||
>
|
>
|
||||||
|
@ -102,8 +99,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}
|
||||||
/>
|
/>
|
||||||
{showInfo ? (
|
{showInfo ? (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -97,18 +97,18 @@ export default async function updateUserById(
|
||||||
id: { not: userId },
|
id: { not: userId },
|
||||||
OR: emailEnabled
|
OR: emailEnabled
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
username: data.username.toLowerCase(),
|
username: data.username.toLowerCase(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
email: data.email?.toLowerCase(),
|
email: data.email?.toLowerCase(),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [
|
: [
|
||||||
{
|
{
|
||||||
username: data.username.toLowerCase(),
|
username: data.username.toLowerCase(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -186,6 +186,7 @@ export default async function updateUserById(
|
||||||
archiveAsScreenshot: data.archiveAsScreenshot,
|
archiveAsScreenshot: data.archiveAsScreenshot,
|
||||||
archiveAsPDF: data.archiveAsPDF,
|
archiveAsPDF: data.archiveAsPDF,
|
||||||
archiveAsWaybackMachine: data.archiveAsWaybackMachine,
|
archiveAsWaybackMachine: data.archiveAsWaybackMachine,
|
||||||
|
linksRouteTo: data.linksRouteTo,
|
||||||
password:
|
password:
|
||||||
data.newPassword && data.newPassword !== ""
|
data.newPassword && data.newPassword !== ""
|
||||||
? newHashedPassword
|
? newHashedPassword
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
import useAccountStore from "@/store/account";
|
||||||
|
import { ArchivedFormat, LinkIncludingShortenedCollectionAndTags } from "@/types/global";
|
||||||
|
import { LinksRouteTo } from "@prisma/client";
|
||||||
|
import { pdfAvailable, readabilityAvailable, screenshotAvailable } from "../shared/getArchiveValidity";
|
||||||
|
|
||||||
|
export const generateLinkHref = (link: LinkIncludingShortenedCollectionAndTags): string => {
|
||||||
|
const { account } = useAccountStore();
|
||||||
|
|
||||||
|
// Return the links href based on the account's preference
|
||||||
|
// If the user's preference is not available, return the original link
|
||||||
|
switch (account.linksRouteTo) {
|
||||||
|
case LinksRouteTo.ORIGINAL:
|
||||||
|
return link.url || '';
|
||||||
|
case LinksRouteTo.PDF:
|
||||||
|
if (!pdfAvailable(link)) return link.url || '';
|
||||||
|
|
||||||
|
return `/preserved/${link?.id}?format=${ArchivedFormat.pdf}`;
|
||||||
|
case LinksRouteTo.READABLE:
|
||||||
|
if (!readabilityAvailable(link)) return link.url || '';
|
||||||
|
|
||||||
|
return `/preserved/${link?.id}?format=${ArchivedFormat.readability}`;
|
||||||
|
case LinksRouteTo.SCREENSHOT:
|
||||||
|
if (!screenshotAvailable(link)) return link.url || '';
|
||||||
|
|
||||||
|
return `/preserved/${link?.id}?format=${link?.image?.endsWith("png") ? ArchivedFormat.png : ArchivedFormat.jpeg}`;
|
||||||
|
default:
|
||||||
|
return link.url || '';
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,4 +1,6 @@
|
||||||
export function screenshotAvailable(link: any) {
|
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
|
||||||
|
|
||||||
|
export function screenshotAvailable(link: LinkIncludingShortenedCollectionAndTags) {
|
||||||
return (
|
return (
|
||||||
link &&
|
link &&
|
||||||
link.image &&
|
link.image &&
|
||||||
|
@ -7,13 +9,13 @@ export function screenshotAvailable(link: any) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pdfAvailable(link: any) {
|
export function pdfAvailable(link: LinkIncludingShortenedCollectionAndTags) {
|
||||||
return (
|
return (
|
||||||
link && link.pdf && link.pdf !== "pending" && link.pdf !== "unavailable"
|
link && link.pdf && link.pdf !== "pending" && link.pdf !== "unavailable"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readabilityAvailable(link: any) {
|
export function readabilityAvailable(link: LinkIncludingShortenedCollectionAndTags) {
|
||||||
return (
|
return (
|
||||||
link &&
|
link &&
|
||||||
link.readable &&
|
link.readable &&
|
||||||
|
|
|
@ -7,6 +7,7 @@ import React from "react";
|
||||||
import useLocalSettingsStore from "@/store/localSettings";
|
import useLocalSettingsStore from "@/store/localSettings";
|
||||||
import Checkbox from "@/components/Checkbox";
|
import Checkbox from "@/components/Checkbox";
|
||||||
import SubmitButton from "@/components/SubmitButton";
|
import SubmitButton from "@/components/SubmitButton";
|
||||||
|
import { LinksRouteTo } from "@prisma/client";
|
||||||
|
|
||||||
export default function Appearance() {
|
export default function Appearance() {
|
||||||
const { updateSettings } = useLocalSettingsStore();
|
const { updateSettings } = useLocalSettingsStore();
|
||||||
|
@ -20,6 +21,9 @@ export default function Appearance() {
|
||||||
const [archiveAsPDF, setArchiveAsPDF] = useState<boolean>(false);
|
const [archiveAsPDF, setArchiveAsPDF] = useState<boolean>(false);
|
||||||
const [archiveAsWaybackMachine, setArchiveAsWaybackMachine] =
|
const [archiveAsWaybackMachine, setArchiveAsWaybackMachine] =
|
||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
|
const [linksRouteTo, setLinksRouteTo] = useState<LinksRouteTo>(
|
||||||
|
user.linksRouteTo
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setUser({
|
setUser({
|
||||||
|
@ -27,8 +31,15 @@ export default function Appearance() {
|
||||||
archiveAsScreenshot,
|
archiveAsScreenshot,
|
||||||
archiveAsPDF,
|
archiveAsPDF,
|
||||||
archiveAsWaybackMachine,
|
archiveAsWaybackMachine,
|
||||||
|
linksRouteTo,
|
||||||
});
|
});
|
||||||
}, [account, archiveAsScreenshot, archiveAsPDF, archiveAsWaybackMachine]);
|
}, [
|
||||||
|
account,
|
||||||
|
archiveAsScreenshot,
|
||||||
|
archiveAsPDF,
|
||||||
|
archiveAsWaybackMachine,
|
||||||
|
linksRouteTo,
|
||||||
|
]);
|
||||||
|
|
||||||
function objectIsEmpty(obj: object) {
|
function objectIsEmpty(obj: object) {
|
||||||
return Object.keys(obj).length === 0;
|
return Object.keys(obj).length === 0;
|
||||||
|
@ -39,6 +50,7 @@ export default function Appearance() {
|
||||||
setArchiveAsScreenshot(account.archiveAsScreenshot);
|
setArchiveAsScreenshot(account.archiveAsScreenshot);
|
||||||
setArchiveAsPDF(account.archiveAsPDF);
|
setArchiveAsPDF(account.archiveAsPDF);
|
||||||
setArchiveAsWaybackMachine(account.archiveAsWaybackMachine);
|
setArchiveAsWaybackMachine(account.archiveAsWaybackMachine);
|
||||||
|
setLinksRouteTo(account.linksRouteTo);
|
||||||
}
|
}
|
||||||
}, [account]);
|
}, [account]);
|
||||||
|
|
||||||
|
@ -134,6 +146,71 @@ export default function Appearance() {
|
||||||
<div className="divider my-3"></div>
|
<div className="divider my-3"></div>
|
||||||
|
|
||||||
<p>Clicking on Links should:</p>
|
<p>Clicking on Links should:</p>
|
||||||
|
<div className="p-3">
|
||||||
|
<label
|
||||||
|
className="label cursor-pointer flex gap-2 justify-start"
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="link-preference-radio"
|
||||||
|
className="radio checked:bg-primary"
|
||||||
|
value="Original"
|
||||||
|
checked={linksRouteTo === LinksRouteTo.ORIGINAL}
|
||||||
|
onChange={() => setLinksRouteTo(LinksRouteTo.ORIGINAL)}
|
||||||
|
/>
|
||||||
|
<span className="label-text">Open the original content</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label
|
||||||
|
className="label cursor-pointer flex gap-2 justify-start"
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="link-preference-radio"
|
||||||
|
className="radio checked:bg-primary"
|
||||||
|
value="PDF"
|
||||||
|
checked={linksRouteTo === LinksRouteTo.PDF}
|
||||||
|
onChange={() => setLinksRouteTo(LinksRouteTo.PDF)}
|
||||||
|
/>
|
||||||
|
<span className="label-text">Open PDF, if available</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label
|
||||||
|
className="label cursor-pointer flex gap-2 justify-start"
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="link-preference-radio"
|
||||||
|
className="radio checked:bg-primary"
|
||||||
|
value="Readable"
|
||||||
|
checked={linksRouteTo === LinksRouteTo.READABLE}
|
||||||
|
onChange={() => setLinksRouteTo(LinksRouteTo.READABLE)}
|
||||||
|
/>
|
||||||
|
<span className="label-text">Open Readable, if available</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label
|
||||||
|
className="label cursor-pointer flex gap-2 justify-start"
|
||||||
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="link-preference-radio"
|
||||||
|
className="radio checked:bg-primary"
|
||||||
|
value="Screenshot"
|
||||||
|
checked={linksRouteTo === LinksRouteTo.SCREENSHOT}
|
||||||
|
onChange={() => setLinksRouteTo(LinksRouteTo.SCREENSHOT)}
|
||||||
|
/>
|
||||||
|
<span className="label-text">Open Screenshot, if available</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
|
|
Ŝarĝante…
Reference in New Issue