finished the public page
This commit is contained in:
@@ -20,7 +20,7 @@ export default function dashboardItem({ name, value, icon }: Props) {
|
||||
<p className="text-gray-500 dark:text-gray-400 text-sm tracking-wider">
|
||||
{name}
|
||||
</p>
|
||||
<p className="font-thin text-6xl text-sky-500 dark:text-sky-500">
|
||||
<p className="font-thin text-6xl text-sky-500 dark:text-sky-500 mt-2">
|
||||
{value}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function FilterSearchDropdown({
|
||||
}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Text Content"
|
||||
label="Full Content"
|
||||
state={searchFilter.textContent}
|
||||
onClick={() =>
|
||||
setSearchFilter({
|
||||
|
||||
@@ -20,7 +20,7 @@ type Props = {
|
||||
onClick?: Function;
|
||||
};
|
||||
|
||||
export default function SettingsSidebar({ className, onClick }: Props) {
|
||||
export default function LinkSidebar({ className, onClick }: Props) {
|
||||
const session = useSession();
|
||||
const userId = session.data?.user.id;
|
||||
|
||||
|
||||
@@ -27,7 +27,14 @@ export default function PreservedFormats() {
|
||||
useEffect(() => {
|
||||
let interval: NodeJS.Timer | undefined;
|
||||
if (link?.screenshotPath === "pending" || link?.pdfPath === "pending") {
|
||||
interval = setInterval(() => getLink(link.id as number), 5000);
|
||||
let isPublicRoute = router.pathname.startsWith("/public")
|
||||
? true
|
||||
: undefined;
|
||||
|
||||
interval = setInterval(
|
||||
() => getLink(link.id as number, isPublicRoute),
|
||||
5000
|
||||
);
|
||||
} else {
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
|
||||
@@ -38,6 +38,7 @@ export default function ProfilePhoto({ src, className, priority }: Props) {
|
||||
width={112}
|
||||
priority={priority}
|
||||
draggable={false}
|
||||
onError={() => setImage("")}
|
||||
className={`h-10 w-10 bg-sky-600 dark:bg-sky-600 shadow rounded-full aspect-square border border-slate-200 dark:border-neutral-700 ${
|
||||
className || ""
|
||||
}`}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Link as LinkType, Tag } from "@prisma/client";
|
||||
import isValidUrl from "@/lib/client/isValidUrl";
|
||||
import unescapeString from "@/lib/client/unescapeString";
|
||||
import { TagIncludingLinkCount } from "@/types/global";
|
||||
import Link from "next/link";
|
||||
|
||||
interface LinksIncludingTags extends LinkType {
|
||||
tags: TagIncludingLinkCount[];
|
||||
@@ -27,75 +28,69 @@ export default function LinkCard({ link, count }: Props) {
|
||||
});
|
||||
|
||||
return (
|
||||
<a href={link.url} target="_blank" rel="noreferrer" className="rounded-3xl">
|
||||
<div className="border border-solid border-sky-100 bg-gradient-to-tr from-slate-200 from-10% to-gray-50 via-20% shadow-md sm:hover:shadow-none duration-100 rounded-3xl cursor-pointer p-5 flex items-start relative gap-5 sm:gap-10 group/item">
|
||||
{url && (
|
||||
<>
|
||||
<Image
|
||||
src={`https://t2.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${url.origin}&size=32`}
|
||||
width={42}
|
||||
height={42}
|
||||
alt=""
|
||||
className="select-none mt-3 z-10 rounded-md shadow border-[3px] border-white bg-white"
|
||||
draggable="false"
|
||||
onError={(e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
target.style.display = "none";
|
||||
}}
|
||||
/>
|
||||
<Image
|
||||
src={`https://t2.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${url.origin}&size=32`}
|
||||
width={80}
|
||||
height={80}
|
||||
alt=""
|
||||
className="blur-sm absolute left-2 opacity-40 select-none hidden sm:block"
|
||||
draggable="false"
|
||||
onError={(e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
target.style.display = "none";
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<div className="flex justify-between items-center gap-5 w-full h-full z-0">
|
||||
<div className="flex flex-col justify-between">
|
||||
<div className="flex items-baseline gap-1">
|
||||
<p className="text-xs text-gray-500">{count + 1}</p>
|
||||
<p className="text-lg text-black">
|
||||
{unescapeString(link.name || link.description)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p className="text-gray-500 text-sm font-medium">
|
||||
{unescapeString(link.description)}
|
||||
<div className="border border-solid border-sky-100 dark:border-neutral-700 bg-gradient-to-tr from-slate-200 dark:from-neutral-800 from-10% to-gray-50 dark:to-[#303030] via-20% shadow hover:shadow-none duration-100 rounded-lg p-3 flex items-start relative gap-3 group/item">
|
||||
<div className="flex justify-between items-end gap-5 w-full h-full z-0">
|
||||
<div className="flex flex-col justify-between w-full">
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="text-2xl">
|
||||
{url && (
|
||||
<Image
|
||||
src={`https://t2.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${url.origin}&size=32`}
|
||||
width={30}
|
||||
height={30}
|
||||
alt=""
|
||||
className="select-none z-10 rounded-md shadow border-[1px] border-white bg-white float-left mr-2"
|
||||
draggable="false"
|
||||
onError={(e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
target.style.display = "none";
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{unescapeString(link.name || link.description)}
|
||||
</p>
|
||||
<div className="flex gap-3 items-center flex-wrap my-3">
|
||||
<div className="flex gap-1 items-center flex-wrap mt-1">
|
||||
{link.tags.map((e, i) => (
|
||||
<p
|
||||
key={i}
|
||||
className="px-2 py-1 bg-sky-200 text-black text-xs rounded-3xl cursor-pointer truncate max-w-[10rem]"
|
||||
>
|
||||
{e.name}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2 items-center flex-wrap mt-2">
|
||||
<p className="text-gray-500">{formattedDate}</p>
|
||||
<div className="text-black flex items-center gap-1">
|
||||
<p>{url ? url.host : link.url}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3 items-center flex-wrap my-2">
|
||||
<div className="flex gap-1 items-center flex-wrap">
|
||||
{link.tags.map((e, i) => (
|
||||
<Link
|
||||
href={"/public/collections/20?q=" + e.name}
|
||||
key={i}
|
||||
className="px-2 text-xs rounded-md border border-black dark:border-white truncate max-w-[10rem] hover:opacity-50 duration-100"
|
||||
>
|
||||
{e.name}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="hidden sm:group-hover/item:block duration-100 text-slate-500">
|
||||
<FontAwesomeIcon
|
||||
icon={faChevronRight}
|
||||
className="w-7 h-7 slide-right-with-fade"
|
||||
/>
|
||||
<div className="flex gap-1 items-center flex-wrap text-sm text-gray-500 dark:text-gray-300">
|
||||
<p>{formattedDate}</p>
|
||||
<p>·</p>
|
||||
<Link
|
||||
href={url ? url.href : link.url}
|
||||
target="_blank"
|
||||
className="hover:opacity-50 duration-100 truncate w-52 sm:w-fit"
|
||||
title={url ? url.href : link.url}
|
||||
>
|
||||
{url ? url.host : link.url}
|
||||
</Link>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
{unescapeString(link.description)}{" "}
|
||||
<Link
|
||||
href={`/public/links/${link.id}`}
|
||||
className="flex gap-1 items-center flex-wrap text-sm text-gray-500 dark:text-gray-300 hover:opacity-50 duration-100 min-w-fit float-right mt-1 ml-2"
|
||||
>
|
||||
<p>Read</p>
|
||||
<FontAwesomeIcon
|
||||
icon={faChevronRight}
|
||||
className="w-3 h-3 mt-[0.15rem]"
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,11 +11,13 @@ type Props = {
|
||||
export default function PublicSearchBar({ placeHolder }: Props) {
|
||||
const router = useRouter();
|
||||
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [searchQuery, setSearchQuery] = useState<string>("");
|
||||
|
||||
useEffect(() => {
|
||||
console.log(router);
|
||||
});
|
||||
router.query.q
|
||||
? setSearchQuery(decodeURIComponent(router.query.q as string))
|
||||
: setSearchQuery("");
|
||||
}, [router.query.q]);
|
||||
|
||||
return (
|
||||
<div className="flex items-center relative group">
|
||||
@@ -36,16 +38,21 @@ export default function PublicSearchBar({ placeHolder }: Props) {
|
||||
toast.error("The search query should not contain '%'.");
|
||||
setSearchQuery(e.target.value.replace("%", ""));
|
||||
}}
|
||||
onKeyDown={(e) =>
|
||||
e.key === "Enter" &&
|
||||
router.push(
|
||||
"/public/collections/" +
|
||||
router.query.id +
|
||||
"?q=" +
|
||||
encodeURIComponent(searchQuery)
|
||||
)
|
||||
}
|
||||
className="border text-sm border-sky-100 bg-white dark:border-neutral-700 focus:border-sky-300 dark:focus:border-sky-600 rounded-md pl-7 py-1 pr-1 w-44 sm:w-60 dark:hover:border-neutral-600 md:focus:w-80 hover:border-sky-300 duration-100 outline-none dark:bg-neutral-800"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
if (!searchQuery) {
|
||||
return router.push("/public/collections/" + router.query.id);
|
||||
}
|
||||
|
||||
return router.push(
|
||||
"/public/collections/" +
|
||||
router.query.id +
|
||||
"?q=" +
|
||||
encodeURIComponent(searchQuery || "")
|
||||
);
|
||||
}
|
||||
}}
|
||||
className="border text-sm border-sky-100 bg-gray-50 dark:border-neutral-700 focus:border-sky-300 dark:focus:border-sky-600 rounded-md pl-8 py-2 pr-2 w-44 sm:w-60 dark:hover:border-neutral-600 md:focus:w-80 hover:border-sky-300 duration-100 outline-none dark:bg-neutral-800"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user