Merge pull request #131 from g1sbi/feat/dark-mode

Feat: Dark mode
This commit is contained in:
Daniel 2023-08-14 23:27:07 -04:00 committed by GitHub
commit da92d46f7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 542 additions and 335 deletions

View File

@ -11,9 +11,7 @@ type Props = {
export default function Checkbox({ label, state, className, onClick }: Props) { export default function Checkbox({ label, state, className, onClick }: Props) {
return ( return (
<label <label className={`cursor-pointer flex items-center gap-2 ${className}`}>
className={`cursor-pointer flex items-center gap-2 text-sky-700 ${className}`}
>
<input <input
type="checkbox" type="checkbox"
checked={state} checked={state}
@ -22,13 +20,15 @@ export default function Checkbox({ label, state, className, onClick }: Props) {
/> />
<FontAwesomeIcon <FontAwesomeIcon
icon={faSquareCheck} icon={faSquareCheck}
className="w-5 h-5 text-sky-700 peer-checked:block hidden" className="w-5 h-5 text-sky-500 dark:text-sky-300 peer-checked:block hidden"
/> />
<FontAwesomeIcon <FontAwesomeIcon
icon={faSquare} icon={faSquare}
className="w-5 h-5 text-sky-700 peer-checked:hidden block" className="w-5 h-5 text-sky-500 dark:text-sky-300 peer-checked:hidden block"
/> />
<span className="text-sky-900 rounded select-none">{label}</span> <span className="text-black dark:text-white rounded select-none">
{label}
</span>
</label> </label>
); );
} }

View File

@ -32,24 +32,24 @@ export default function CollectionCard({ collection, className }: Props) {
return ( return (
<div <div
className={`bg-gradient-to-tr from-sky-100 from-10% via-gray-100 via-20% to-white to-100% self-stretch min-h-[12rem] rounded-2xl shadow duration-100 hover:shadow-none group relative ${className}`} className={`bg-gradient-to-tr from-sky-100 dark:from-gray-800 from-10% via-gray-100 via-20% to-white dark:to-neutral-800 to-100% self-stretch min-h-[12rem] rounded-2xl shadow duration-100 hover:shadow-none group relative ${className}`}
> >
<div <div
onClick={() => setExpandDropdown(!expandDropdown)} onClick={() => setExpandDropdown(!expandDropdown)}
id={"expand-dropdown" + collection.id} id={"expand-dropdown" + collection.id}
className="inline-flex absolute top-5 right-5 rounded-md cursor-pointer hover:bg-slate-200 duration-100 p-1" className="inline-flex absolute top-5 right-5 rounded-md cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faEllipsis} icon={faEllipsis}
id={"expand-dropdown" + collection.id} id={"expand-dropdown" + collection.id}
className="w-5 h-5 text-gray-500" className="w-5 h-5 text-gray-500 dark:text-gray-300"
/> />
</div> </div>
<Link <Link
href={`/collections/${collection.id}`} href={`/collections/${collection.id}`}
className="flex flex-col gap-2 justify-between min-h-[12rem] h-full select-none p-5" className="flex flex-col gap-2 justify-between min-h-[12rem] h-full select-none p-5"
> >
<p className="text-2xl font-bold capitalize text-sky-700 break-words line-clamp-3 w-4/5"> <p className="text-2xl capitalize text-black dark:text-white break-words line-clamp-3 w-4/5">
{collection.name} {collection.name}
</p> </p>
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
@ -73,11 +73,14 @@ export default function CollectionCard({ collection, className }: Props) {
) : null} ) : null}
</div> </div>
<div className="text-right w-40"> <div className="text-right w-40">
<div className="text-sky-700 font-bold text-sm flex justify-end gap-1 items-center"> <div className="text-black dark:text-white font-bold text-sm flex justify-end gap-1 items-center">
<FontAwesomeIcon icon={faLink} className="w-5 h-5 text-sky-500" /> <FontAwesomeIcon
icon={faLink}
className="w-5 h-5 text-black dark:text-white"
/>
{collection._count && collection._count.links} {collection._count && collection._count.links}
</div> </div>
<div className="flex items-center justify-end gap-1 text-gray-600"> <div className="flex items-center justify-end gap-1 text-gray-600 dark:text-white">
<FontAwesomeIcon icon={faCalendarDays} className="w-4 h-4" /> <FontAwesomeIcon icon={faCalendarDays} className="w-4 h-4" />
<p className="font-bold text-xs">{formattedDate}</p> <p className="font-bold text-xs">{formattedDate}</p>
</div> </div>

View File

@ -25,13 +25,13 @@ export default function Dropdown({ onClickOutside, className, items }: Props) {
return ( return (
<ClickAwayHandler <ClickAwayHandler
onClickOutside={onClickOutside} onClickOutside={onClickOutside}
className={`${className} py-1 shadow-md border border-sky-100 bg-gray-50 rounded-md flex flex-col z-20`} className={`${className} py-1 shadow-md border border-sky-100 dark:border-neutral-700 bg-gray-50 dark:bg-neutral-800 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-slate-200 duration-100"> <div className="flex items-center gap-2 py-1 px-2 hover:bg-slate-200 dark:hover:bg-neutral-700 duration-100">
<p className="text-sky-900 select-none">{e.name}</p> <p className="text-black dark:text-white select-none">{e.name}</p>
</div> </div>
</div> </div>
); );

View File

@ -20,9 +20,11 @@ export default function FilterSearchDropdown({
const target = e.target as HTMLInputElement; const target = e.target as HTMLInputElement;
if (target.id !== "filter-dropdown") setFilterDropdown(false); if (target.id !== "filter-dropdown") setFilterDropdown(false);
}} }}
className="absolute top-8 right-0 border border-sky-100 shadow-md bg-gray-50 rounded-md p-2 z-20 w-40" className="absolute top-8 right-0 border border-sky-100 dark:border-neutral-700 shadow-md bg-gray-50 dark:bg-neutral-800 rounded-md p-2 z-20 w-40"
> >
<p className="mb-2 text-sky-900 text-center font-semibold">Filter by</p> <p className="mb-2 text-black dark:text-white text-center font-semibold">
Filter by
</p>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<Checkbox <Checkbox
label="Name" label="Name"

View File

@ -45,6 +45,8 @@ export default function CollectionSelection({ onChange, defaultValue }: Props) {
return ( return (
<Select <Select
isClearable isClearable
className="react-select-container"
classNamePrefix="react-select"
placeholder="Default: Unnamed Collection" placeholder="Default: Unnamed Collection"
onChange={onChange} onChange={onChange}
options={options} options={options}

View File

@ -28,6 +28,8 @@ export default function TagSelection({ onChange, defaultValue }: Props) {
return ( return (
<CreatableSelect <CreatableSelect
isClearable isClearable
className="react-select-container"
classNamePrefix="react-select"
onChange={onChange} onChange={onChange}
options={options} options={options}
styles={styles} styles={styles}

View File

@ -106,7 +106,7 @@ export default function LinkCard({ link, count, className }: Props) {
return ( return (
<div <div
className={`bg-gradient-to-tr from-slate-200 from-10% to-gray-50 via-20% shadow hover:shadow-none cursor-pointer duration-100 rounded-2xl relative group ${className}`} className={`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 cursor-pointer duration-100 rounded-2xl relative group ${className}`}
> >
{(permissions === true || {(permissions === true ||
permissions?.canUpdate || permissions?.canUpdate ||
@ -114,7 +114,7 @@ export default function LinkCard({ link, count, className }: Props) {
<div <div
onClick={() => setExpandDropdown(!expandDropdown)} onClick={() => setExpandDropdown(!expandDropdown)}
id={"expand-dropdown" + link.id} id={"expand-dropdown" + link.id}
className="text-gray-500 inline-flex rounded-md cursor-pointer hover:bg-slate-200 absolute right-5 top-5 z-10 duration-100 p-1" className="text-gray-500 dark:text-gray-300 inline-flex rounded-md cursor-pointer hover:bg-slate-200 dark:hover:bg-neutral-700 absolute right-5 top-5 z-10 duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faEllipsis} icon={faEllipsis}
@ -156,8 +156,10 @@ export default function LinkCard({ link, count, className }: Props) {
<div className="flex justify-between gap-5 w-full h-full z-0"> <div className="flex justify-between gap-5 w-full h-full z-0">
<div className="flex flex-col justify-between w-full"> <div className="flex flex-col justify-between w-full">
<div className="flex items-baseline gap-1"> <div className="flex items-baseline gap-1">
<p className="text-sm text-sky-500 font-bold">{count + 1}.</p> <p className="text-sm text-gray-500 dark:text-gray-300">
<p className="text-lg text-sky-700 font-bold truncate capitalize w-full pr-8"> {count + 1}
</p>
<p className="text-lg text-black dark:text-white truncate capitalize w-full pr-8">
{link.name || link.description} {link.name || link.description}
</p> </p>
</div> </div>
@ -168,16 +170,16 @@ export default function LinkCard({ link, count, className }: Props) {
className="w-4 h-4 mt-1 drop-shadow" className="w-4 h-4 mt-1 drop-shadow"
style={{ color: collection?.color }} style={{ color: collection?.color }}
/> />
<p className="text-sky-900 truncate capitalize"> <p className="text-black dark:text-white truncate capitalize">
{collection?.name} {collection?.name}
</p> </p>
</div> </div>
</div> </div>
<div className="flex items-center gap-1 w-full pr-20 text-gray-500"> <div className="flex items-center gap-1 w-full pr-20 text-gray-500 dark:text-gray-300">
<FontAwesomeIcon icon={faLink} className="mt-1 w-4 h-4" /> <FontAwesomeIcon icon={faLink} className="mt-1 w-4 h-4" />
<p className="truncate w-full">{shortendURL}</p> <p className="truncate w-full">{shortendURL}</p>
</div> </div>
<div className="flex items-center gap-1 text-gray-500"> <div className="flex items-center gap-1 text-gray-500 dark:text-gray-300">
<FontAwesomeIcon icon={faCalendarDays} className="w-4 h-4" /> <FontAwesomeIcon icon={faCalendarDays} className="w-4 h-4" />
<p>{formattedDate}</p> <p>{formattedDate}</p>
</div> </div>

View File

@ -60,7 +60,7 @@ export default function CollectionInfo({
<div className="flex flex-col gap-3 sm:w-[35rem] w-80"> <div className="flex flex-col gap-3 sm:w-[35rem] w-80">
<div className="flex flex-col sm:flex-row gap-3"> <div className="flex flex-col sm:flex-row gap-3">
<div className="w-full"> <div className="w-full">
<p className="text-sm text-sky-700 mb-2"> <p className="text-sm text-black dark:text-white mb-2">
Name Name
<RequiredBadge /> <RequiredBadge />
</p> </p>
@ -72,11 +72,13 @@ export default function CollectionInfo({
} }
type="text" type="text"
placeholder="e.g. Example Collection" placeholder="e.g. Example Collection"
className="w-full rounded-md p-3 border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-3 dark:bg-neutral-900 border-solid border outline-none border-sky-100 dark:border-neutral-700 focus:border-sky-300 dark:focus:border-sky-600 duration-100"
/> />
<div className="color-picker flex justify-between"> <div className="color-picker flex justify-between">
<div className="flex flex-col justify-between items-center w-32"> <div className="flex flex-col justify-between items-center w-32">
<p className="text-sm w-full text-sky-700 mb-2">Icon Color</p> <p className="text-sm w-full text-black dark:text-white mb-2">
Icon Color
</p>
<div style={{ color: collection.color }}> <div style={{ color: collection.color }}>
<FontAwesomeIcon <FontAwesomeIcon
icon={faFolder} icon={faFolder}
@ -84,7 +86,7 @@ export default function CollectionInfo({
/> />
</div> </div>
<div <div
className="py-1 px-2 rounded-md text-xs font-semibold cursor-pointer text-sky-700 hover:bg-slate-200 duration-100" className="py-1 px-2 rounded-md text-xs font-semibold cursor-pointer text-black dark:text-white hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100"
onClick={() => onClick={() =>
setCollection({ ...collection, color: "#0ea5e9" }) setCollection({ ...collection, color: "#0ea5e9" })
} }
@ -101,9 +103,9 @@ export default function CollectionInfo({
</div> </div>
<div className="w-full"> <div className="w-full">
<p className="text-sm text-sky-700 mb-2">Description</p> <p className="text-sm text-black dark:text-white mb-2">Description</p>
<textarea <textarea
className="w-full h-[11.4rem] resize-none border rounded-md duration-100 bg-white p-3 outline-none border-sky-100 focus:border-sky-700" className="w-full h-[11.4rem] resize-none border rounded-md duration-100 bg-white dark:bg-neutral-900 p-3 outline-none border-sky-100 dark:border-neutral-700 focus:border-sky-300 dark:focus:border-sky-600"
placeholder="The purpose of this Collection..." placeholder="The purpose of this Collection..."
value={collection.description} value={collection.description}
onChange={(e) => onChange={(e) =>

View File

@ -50,7 +50,7 @@ export default function DeleteCollection({
<p className="text-red-500 font-bold text-center">Warning!</p> <p className="text-red-500 font-bold text-center">Warning!</p>
<div className="max-h-[20rem] overflow-y-auto"> <div className="max-h-[20rem] overflow-y-auto">
<div className="text-gray-500"> <div className="text-gray-500 dark:text-white">
<p> <p>
Please note that deleting the collection will permanently remove Please note that deleting the collection will permanently remove
all its contents, including the following: all its contents, including the following:
@ -81,9 +81,9 @@ export default function DeleteCollection({
</div> </div>
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<p className="text-sky-900 select-none text-center"> <p className="text-black dark:text-white select-none text-center">
To confirm, type &quot; To confirm, type &quot;
<span className="font-bold text-sky-700">{collection.name}</span> <span className="font-bold">{collection.name}</span>
&quot; in the box below: &quot; in the box below:
</p> </p>
@ -93,12 +93,12 @@ export default function DeleteCollection({
onChange={(e) => setInputField(e.target.value)} onChange={(e) => setInputField(e.target.value)}
type="text" type="text"
placeholder={`Type "${collection.name}" Here.`} placeholder={`Type "${collection.name}" Here.`}
className="w-72 sm:w-96 rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-72 sm:w-96 rounded-md p-3 mx-auto border-sky-100 dark:border-neutral-700 focus:border-sky-300 dark:focus:border-sky-600 dark:bg-neutral-900 border-solid border outline-none duration-100"
/> />
</div> </div>
</> </>
) : ( ) : (
<p className="text-gray-500"> <p className="text-gray-500 dark:text-white">
Click the button below to leave the current collection: Click the button below to leave the current collection:
</p> </p>
)} )}
@ -107,9 +107,9 @@ export default function DeleteCollection({
className={`mx-auto mt-2 text-white flex items-center gap-2 py-2 px-5 rounded-md select-none font-bold duration-100 ${ className={`mx-auto mt-2 text-white flex items-center gap-2 py-2 px-5 rounded-md select-none font-bold duration-100 ${
permissions === true permissions === true
? inputField === collection.name ? inputField === collection.name
? "bg-red-500 hover:bg-red-400 cursor-pointer" ? "bg-red-500 hover:bg-red-400 hover:dark:bg-red-600 cursor-pointer"
: "cursor-not-allowed bg-red-300" : "cursor-not-allowed bg-red-300 dark:bg-red-900"
: "bg-red-500 hover:bg-red-400 cursor-pointer" : "bg-red-500 hover:bg-red-400 hover:dark:bg-red-600 cursor-pointer"
}`} }`}
onClick={submit} onClick={submit}
> >

View File

@ -117,7 +117,7 @@ export default function TeamManagement({
<div className="flex flex-col gap-3 sm:w-[35rem] w-80"> <div className="flex flex-col gap-3 sm:w-[35rem] w-80">
{permissions === true && ( {permissions === true && (
<> <>
<p className="text-sm text-sky-700">Make Public</p> <p className="text-sm text-black dark:text-white">Make Public</p>
<Checkbox <Checkbox
label="Make this a public collection." label="Make this a public collection."
@ -127,7 +127,7 @@ export default function TeamManagement({
} }
/> />
<p className="text-gray-500 text-sm"> <p className="text-gray-500 dark:text-white text-sm">
This will let <b>Anyone</b> to view this collection. This will let <b>Anyone</b> to view this collection.
</p> </p>
</> </>
@ -135,7 +135,7 @@ export default function TeamManagement({
{collection.isPublic ? ( {collection.isPublic ? (
<div> <div>
<p className="text-sm text-sky-700 mb-2"> <p className="text-sm text-black dark:text-white mb-2">
Public Link (Click to copy) Public Link (Click to copy)
</p> </p>
<div <div
@ -148,7 +148,7 @@ export default function TeamManagement({
console.log(err); console.log(err);
} }
}} }}
className="w-full hide-scrollbar overflow-x-auto whitespace-nowrap rounded-md p-3 border-sky-100 border-solid border outline-none hover:border-sky-700 duration-100 cursor-text" className="w-full hide-scrollbar overflow-x-auto whitespace-nowrap rounded-md p-3 border-sky-100 dark:border-neutral-700 border-solid border outline-none hover:border-sky-300 dark:hover:border-sky-600 duration-100 cursor-text"
> >
{publicCollectionURL} {publicCollectionURL}
</div> </div>
@ -159,7 +159,9 @@ export default function TeamManagement({
{permissions === true && ( {permissions === true && (
<> <>
<p className="text-sm text-sky-700">Member Management</p> <p className="text-sm text-black dark:text-white">
Member Management
</p>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<input <input
@ -181,7 +183,7 @@ export default function TeamManagement({
} }
type="text" type="text"
placeholder="Username (without the '@')" placeholder="Username (without the '@')"
className="w-full rounded-md p-3 border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-3 dark:bg-neutral-900 border-solid border outline-none border-sky-100 dark:border-neutral-700 focus:border-sky-300 dark:focus:border-sky-600 duration-100"
/> />
<div <div
@ -193,7 +195,7 @@ export default function TeamManagement({
setMemberState setMemberState
) )
} }
className="flex items-center justify-center bg-sky-700 hover:bg-sky-600 duration-100 text-white w-12 h-12 p-3 rounded-md cursor-pointer" className="flex items-center justify-center bg-sky-700 dark:bg-sky-400 hover:bg-sky-600 duration-100 text-white w-12 h-12 p-3 rounded-md cursor-pointer"
> >
<FontAwesomeIcon icon={faUserPlus} className="w-5 h-5" /> <FontAwesomeIcon icon={faUserPlus} className="w-5 h-5" />
</div> </div>
@ -203,7 +205,7 @@ export default function TeamManagement({
{collection?.members[0]?.user && ( {collection?.members[0]?.user && (
<> <>
<p className="text-center text-gray-500 text-xs sm:text-sm"> <p className="text-center text-gray-500 dark:text-white text-xs sm:text-sm">
(All Members have <b>Read</b> access to this collection.) (All Members have <b>Read</b> access to this collection.)
</p> </p>
<div className="flex flex-col gap-3 rounded-md"> <div className="flex flex-col gap-3 rounded-md">
@ -213,12 +215,12 @@ export default function TeamManagement({
return ( return (
<div <div
key={i} key={i}
className="relative border p-2 rounded-md border-sky-100 flex flex-col sm:flex-row sm:items-center gap-2 justify-between" className="relative border p-2 rounded-md border-sky-100 dark:border-neutral-700 flex flex-col sm:flex-row sm:items-center gap-2 justify-between"
> >
{permissions === true && ( {permissions === true && (
<FontAwesomeIcon <FontAwesomeIcon
icon={faClose} icon={faClose}
className="absolute right-2 top-2 text-gray-500 h-4 hover:text-red-500 duration-100 cursor-pointer" className="absolute right-2 top-2 text-gray-500 dark:text-white h-4 hover:text-red-500 duration-100 cursor-pointer"
title="Remove Member" title="Remove Member"
onClick={() => { onClick={() => {
const updatedMembers = collection.members.filter( const updatedMembers = collection.members.filter(
@ -239,23 +241,25 @@ export default function TeamManagement({
className="border-[3px]" className="border-[3px]"
/> />
<div> <div>
<p className="text-sm font-bold text-sky-700"> <p className="text-sm font-bold text-black dark:text-white">
{e.user.name} {e.user.name}
</p> </p>
<p className="text-sky-900">@{e.user.username}</p> <p className="text-gray-500 dark:text-gray-300">
@{e.user.username}
</p>
</div> </div>
</div> </div>
<div className="flex sm:block items-center gap-5 min-w-[10rem]"> <div className="flex sm:block items-center gap-5 min-w-[10rem]">
<div> <div>
<p <p
className={`font-bold text-sm text-sky-700 ${ className={`font-bold text-sm text-black dark:text-white ${
permissions === true ? "" : "mb-2" permissions === true ? "" : "mb-2"
}`} }`}
> >
Permissions Permissions
</p> </p>
{permissions === true && ( {permissions === true && (
<p className="text-xs text-gray-500 mb-2"> <p className="text-xs text-gray-500 dark:text-white mb-2">
(Click to toggle.) (Click to toggle.)
</p> </p>
)} )}
@ -265,7 +269,7 @@ export default function TeamManagement({
!e.canCreate && !e.canCreate &&
!e.canUpdate && !e.canUpdate &&
!e.canDelete ? ( !e.canDelete ? (
<p className="text-sm text-gray-500"> <p className="text-sm text-gray-500 dark:text-white">
Has no permissions. Has no permissions.
</p> </p>
) : ( ) : (
@ -305,11 +309,11 @@ export default function TeamManagement({
}} }}
/> />
<span <span
className={`text-sky-900 peer-checked:bg-sky-700 text-sm ${ className={`text-black dark:text-white peer-checked:bg-sky-200 dark:peer-checked:bg-sky-600 text-sm ${
permissions === true permissions === true
? "hover:bg-slate-200 duration-75" ? "hover:bg-slate-200 hover:dark:bg-neutral-700 duration-75"
: "" : ""
} peer-checked:text-white rounded p-1 select-none`} } rounded p-1 select-none`}
> >
Create Create
</span> </span>
@ -350,11 +354,11 @@ export default function TeamManagement({
}} }}
/> />
<span <span
className={`text-sky-900 peer-checked:bg-sky-700 text-sm ${ className={`text-black dark:text-white peer-checked:bg-sky-200 dark:peer-checked:bg-sky-600 text-sm ${
permissions === true permissions === true
? "hover:bg-slate-200 duration-75" ? "hover:bg-slate-200 hover:dark:bg-neutral-700 duration-75"
: "" : ""
} peer-checked:text-white rounded p-1 select-none`} } rounded p-1 select-none`}
> >
Update Update
</span> </span>
@ -395,11 +399,11 @@ export default function TeamManagement({
}} }}
/> />
<span <span
className={`text-sky-900 peer-checked:bg-sky-700 text-sm ${ className={`text-black dark:text-white peer-checked:bg-sky-200 dark:peer-checked:bg-sky-600 text-sm ${
permissions === true permissions === true
? "hover:bg-slate-200 duration-75" ? "hover:bg-slate-200 hover:dark:bg-neutral-700 duration-75"
: "" : ""
} peer-checked:text-white rounded p-1 select-none`} } rounded p-1 select-none`}
> >
Delete Delete
</span> </span>
@ -415,7 +419,7 @@ export default function TeamManagement({
)} )}
<div <div
className="relative border px-2 rounded-md border-sky-100 flex min-h-[7rem] sm:min-h-[5rem] gap-2 justify-between" className="relative border px-2 rounded-md border-sky-100 dark:border-neutral-700 flex min-h-[7rem] sm:min-h-[5rem] gap-2 justify-between"
title={`'@${collectionOwner.username}' is the owner of this collection.`} title={`'@${collectionOwner.username}' is the owner of this collection.`}
> >
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@ -425,7 +429,7 @@ export default function TeamManagement({
/> />
<div> <div>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<p className="text-sm font-bold text-sky-700"> <p className="text-sm font-bold text-black dark:text-white">
{collectionOwner.name} {collectionOwner.name}
</p> </p>
<FontAwesomeIcon <FontAwesomeIcon
@ -433,13 +437,15 @@ export default function TeamManagement({
className="w-3 h-3 text-yellow-500" className="w-3 h-3 text-yellow-500"
/> />
</div> </div>
<p className="text-sky-900">@{collectionOwner.username}</p> <p className="text-gray-500 dark:text-gray-300">
@{collectionOwner.username}
</p>
</div> </div>
</div> </div>
<div className="flex flex-col justify-center min-w-[10rem]"> <div className="flex flex-col justify-center min-w-[10rem] text-black dark:text-white">
<p className={`font-bold text-sm text-sky-700`}>Permissions</p> <p className={`font-bold text-sm`}>Permissions</p>
<p className="text-sky-700">Full Access (Owner)</p> <p>Full Access (Owner)</p>
</div> </div>
</div> </div>

View File

@ -46,17 +46,19 @@ export default function CollectionModal({
<div className={className}> <div className={className}>
<Tab.Group defaultIndex={defaultIndex}> <Tab.Group defaultIndex={defaultIndex}>
{method === "CREATE" && ( {method === "CREATE" && (
<p className="text-xl text-sky-700 text-center">New Collection</p> <p className="text-xl text-black dark:text-white text-center">
New Collection
</p>
)} )}
<Tab.List className="flex justify-center flex-col max-w-[15rem] sm:max-w-[30rem] mx-auto sm:flex-row gap-2 sm:gap-3 mb-5 text-sky-700"> <Tab.List className="flex justify-center flex-col max-w-[15rem] sm:max-w-[30rem] mx-auto sm:flex-row gap-2 sm:gap-3 mb-5 text-black dark:text-white">
{method === "UPDATE" && ( {method === "UPDATE" && (
<> <>
{isOwner && ( {isOwner && (
<Tab <Tab
className={({ selected }) => className={({ selected }) =>
selected selected
? "px-2 py-1 bg-sky-200 duration-100 rounded-md outline-none" ? "px-2 py-1 bg-sky-200 dark:bg-sky-500 dark:text-white duration-100 rounded-md outline-none"
: "px-2 py-1 hover:bg-slate-200 rounded-md duration-100 outline-none" : "px-2 py-1 hover:bg-slate-200 hover:dark:bg-neutral-700 hover:dark:text-white rounded-md duration-100 outline-none"
} }
> >
Collection Info Collection Info
@ -65,8 +67,8 @@ export default function CollectionModal({
<Tab <Tab
className={({ selected }) => className={({ selected }) =>
selected selected
? "px-2 py-1 bg-sky-200 duration-100 rounded-md outline-none" ? "px-2 py-1 bg-sky-200 dark:bg-sky-500 dark:text-white duration-100 rounded-md outline-none"
: "px-2 py-1 hover:bg-slate-200 rounded-md duration-100 outline-none" : "px-2 py-1 hover:bg-slate-200 hover:dark:bg-neutral-700 hover:dark:text-white rounded-md duration-100 outline-none"
} }
> >
{isOwner ? "Share & Collaborate" : "View Team"} {isOwner ? "Share & Collaborate" : "View Team"}
@ -74,8 +76,8 @@ export default function CollectionModal({
<Tab <Tab
className={({ selected }) => className={({ selected }) =>
selected selected
? "px-2 py-1 bg-sky-200 duration-100 rounded-md outline-none" ? "px-2 py-1 bg-sky-200 dark:bg-sky-500 dark:text-white duration-100 rounded-md outline-none"
: "px-2 py-1 hover:bg-slate-200 rounded-md duration-100 outline-none" : "px-2 py-1 hover:bg-slate-200 hover:dark:bg-neutral-700 hover:dark:text-white rounded-md duration-100 outline-none"
} }
> >
{isOwner ? "Delete Collection" : "Leave Collection"} {isOwner ? "Delete Collection" : "Leave Collection"}

View File

@ -115,10 +115,10 @@ export default function AddOrEditLink({
<div className="flex flex-col gap-3 sm:w-[35rem] w-80"> <div className="flex flex-col gap-3 sm:w-[35rem] w-80">
{method === "UPDATE" ? ( {method === "UPDATE" ? (
<p <p
className="text-gray-500 my-2 text-center truncate w-full" className="text-gray-500 dark:text-gray-300 my-2 text-center truncate w-full"
title={link.url} title={link.url}
> >
<Link href={link.url} target="_blank" className=" font-bold"> <Link href={link.url} target="_blank" className="font-bold">
{link.url} {link.url}
</Link> </Link>
</p> </p>
@ -126,7 +126,7 @@ export default function AddOrEditLink({
{method === "CREATE" ? ( {method === "CREATE" ? (
<div> <div>
<p className="text-sm text-sky-700 mb-2 font-bold"> <p className="text-sm text-black dark:text-white mb-2 font-bold">
Address (URL) Address (URL)
<RequiredBadge /> <RequiredBadge />
</p> </p>
@ -135,14 +135,14 @@ export default function AddOrEditLink({
onChange={(e) => setLink({ ...link, url: e.target.value })} onChange={(e) => setLink({ ...link, url: e.target.value })}
type="text" type="text"
placeholder="e.g. http://example.com/" placeholder="e.g. http://example.com/"
className="w-full rounded-md p-2 border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-2 dark:bg-neutral-900 border-solid border outline-none border-sky-100 dark:border-neutral-700 focus:border-sky-300 dark:focus:border-sky-600 duration-100"
/> />
</div> </div>
) : null} ) : null}
<hr /> <hr className="dark:border-neutral-700" />
<div className="grid sm:grid-cols-2 gap-3"> <div className="grid sm:grid-cols-2 gap-3">
<div> <div>
<p className="text-sm text-sky-700 mb-2">Collection</p> <p className="text-sm text-black dark:text-white mb-2">Collection</p>
<CollectionSelection <CollectionSelection
onChange={setCollection} onChange={setCollection}
// defaultValue={{ // defaultValue={{
@ -161,7 +161,7 @@ export default function AddOrEditLink({
</div> </div>
<div> <div>
<p className="text-sm text-sky-700 mb-2">Tags</p> <p className="text-sm text-black dark:text-white mb-2">Tags</p>
<TagSelection <TagSelection
onChange={setTags} onChange={setTags}
defaultValue={link.tags.map((e) => { defaultValue={link.tags.map((e) => {
@ -171,18 +171,18 @@ export default function AddOrEditLink({
</div> </div>
<div className="sm:col-span-2"> <div className="sm:col-span-2">
<p className="text-sm text-sky-700 mb-2">Name</p> <p className="text-sm text-black dark:text-white mb-2">Name</p>
<input <input
value={link.name} value={link.name}
onChange={(e) => setLink({ ...link, name: e.target.value })} onChange={(e) => setLink({ ...link, name: e.target.value })}
type="text" type="text"
placeholder="e.g. Example Link" placeholder="e.g. Example Link"
className="w-full rounded-md p-2 border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-2 dark:bg-neutral-900 border-solid border outline-none border-sky-100 dark:border-neutral-700 focus:border-sky-300 dark:focus:border-sky-600 duration-100"
/> />
</div> </div>
<div className="sm:col-span-2"> <div className="sm:col-span-2">
<p className="text-sm text-sky-700 mb-2">Description</p> <p className="text-sm text-black dark:text-white mb-2">Description</p>
<textarea <textarea
value={link.description} value={link.description}
onChange={(e) => setLink({ ...link, description: e.target.value })} onChange={(e) => setLink({ ...link, description: e.target.value })}
@ -191,7 +191,7 @@ export default function AddOrEditLink({
? "Will be auto generated if nothing is provided." ? "Will be auto generated if nothing is provided."
: "" : ""
} }
className="resize-none w-full rounded-md p-2 border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="resize-none w-full rounded-md p-2 border-sky-100 dark:border-neutral-700 focus:border-sky-300 dark:focus:border-sky-600 border-solid border outline-none duration-100 dark:bg-neutral-900"
/> />
</div> </div>
</div> </div>

View File

@ -20,12 +20,15 @@ import {
faFilePdf, faFilePdf,
} from "@fortawesome/free-regular-svg-icons"; } from "@fortawesome/free-regular-svg-icons";
import isValidUrl from "@/lib/client/isValidUrl"; import isValidUrl from "@/lib/client/isValidUrl";
import { useTheme } from "next-themes";
type Props = { type Props = {
link: LinkIncludingShortenedCollectionAndTags; link: LinkIncludingShortenedCollectionAndTags;
}; };
export default function LinkDetails({ link }: Props) { export default function LinkDetails({ link }: Props) {
const { theme, setTheme } = useTheme();
const [imageError, setImageError] = useState<boolean>(false); const [imageError, setImageError] = useState<boolean>(false);
const formattedDate = new Date(link.createdAt as string).toLocaleString( const formattedDate = new Date(link.createdAt as string).toLocaleString(
"en-US", "en-US",
@ -71,6 +74,9 @@ export default function LinkDetails({ link }: Props) {
useEffect(() => { useEffect(() => {
const banner = document.getElementById("link-banner"); const banner = document.getElementById("link-banner");
const bannerInner = document.getElementById("link-banner-inner"); const bannerInner = document.getElementById("link-banner-inner");
const bannerOut = document.getElementById("link-banner-outside");
if (theme === "dark") bannerOut?.classList.toggle("banner-dark-mode");
if (colorPalette && banner && bannerInner) { if (colorPalette && banner && bannerInner) {
banner.style.background = `linear-gradient(to right, ${rgbToHex( banner.style.background = `linear-gradient(to right, ${rgbToHex(
@ -93,7 +99,7 @@ export default function LinkDetails({ link }: Props) {
colorPalette[3][2] colorPalette[3][2]
)})`; )})`;
} }
}, [colorPalette]); }, [colorPalette, theme]);
const handleDownload = (format: "png" | "pdf") => { const handleDownload = (format: "png" | "pdf") => {
const path = `/api/archives/${link.collection.id}/${link.id}.${format}`; const path = `/api/archives/${link.collection.id}/${link.id}.${format}`;
@ -115,7 +121,10 @@ export default function LinkDetails({ link }: Props) {
}; };
return ( return (
<div className="flex flex-col gap-3 sm:w-[35rem] w-80"> <div
id="link-banner-outside"
className="flex flex-col gap-3 sm:w-[35rem] w-80"
>
{!imageError && ( {!imageError && (
<div id="link-banner" className="link-banner h-32 -mx-5 -mt-5 relative"> <div id="link-banner" className="link-banner h-32 -mx-5 -mt-5 relative">
<div id="link-banner-inner" className="link-banner-inner"></div> <div id="link-banner-inner" className="link-banner-inner"></div>
@ -131,7 +140,7 @@ export default function LinkDetails({ link }: Props) {
height={42} height={42}
alt="" alt=""
id={"favicon-" + link.id} id={"favicon-" + link.id}
className="select-none mt-2 rounded-md shadow border-[3px] border-white bg-white aspect-square" className="select-none mt-2 rounded-md shadow border-[3px] border-white dark:border-neutral-900 bg-white dark:bg-neutral-900 aspect-square"
draggable="false" draggable="false"
onLoad={(e) => { onLoad={(e) => {
try { try {
@ -151,14 +160,14 @@ export default function LinkDetails({ link }: Props) {
/> />
)} )}
<div className="flex flex-col min-h-[3rem] justify-end drop-shadow"> <div className="flex flex-col min-h-[3rem] justify-end drop-shadow">
<p className="text-2xl text-sky-700 capitalize break-words hyphens-auto"> <p className="text-2xl text-black dark:text-white capitalize break-words hyphens-auto">
{link.name} {link.name}
</p> </p>
<Link <Link
href={link.url} href={link.url}
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
className="text-sm text-gray-500 break-all hover:underline cursor-pointer w-fit" className="text-sm text-gray-500 dark:text-gray-300 break-all hover:underline cursor-pointer w-fit"
> >
{url ? url.host : link.url} {url ? url.host : link.url}
</Link> </Link>
@ -176,7 +185,7 @@ export default function LinkDetails({ link }: Props) {
/> />
<p <p
title={collection?.name} title={collection?.name}
className="text-sky-900 text-lg truncate max-w-[12rem]" className="text-black dark:text-white text-lg truncate max-w-[12rem]"
> >
{collection?.name} {collection?.name}
</p> </p>
@ -185,7 +194,7 @@ export default function LinkDetails({ link }: Props) {
<Link key={i} href={`/tags/${e.id}`} className="z-10"> <Link key={i} href={`/tags/${e.id}`} className="z-10">
<p <p
title={e.name} title={e.name}
className="px-2 py-1 bg-sky-200 text-sky-700 text-xs rounded-3xl cursor-pointer hover:opacity-60 duration-100 truncate max-w-[19rem]" className="px-2 py-1 bg-sky-200 text-black dark:text-white dark:bg-sky-900 text-xs rounded-3xl cursor-pointer hover:opacity-60 duration-100 truncate max-w-[19rem]"
> >
{e.name} {e.name}
</p> </p>
@ -194,19 +203,19 @@ export default function LinkDetails({ link }: Props) {
</div> </div>
{link.description && ( {link.description && (
<> <>
<div className="text-gray-500 max-h-[20rem] my-3 rounded-md overflow-y-auto hyphens-auto"> <div className="text-black dark:text-white max-h-[20rem] my-3 rounded-md overflow-y-auto hyphens-auto">
{link.description} {link.description}
</div> </div>
</> </>
)} )}
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<div className="flex items-center gap-1 text-gray-500"> <div className="flex items-center gap-1 text-gray-500 dark:text-gray-300">
<FontAwesomeIcon icon={faBoxArchive} className="w-4 h-4" /> <FontAwesomeIcon icon={faBoxArchive} className="w-4 h-4" />
<p className=" text-gray-500">Archived Formats:</p> <p>Archived Formats:</p>
</div> </div>
<div <div
className="flex items-center gap-1 text-gray-500" className="flex items-center gap-1 text-gray-500 dark:text-gray-300"
title={"Created at: " + formattedDate} title={"Created at: " + formattedDate}
> >
<FontAwesomeIcon icon={faCalendarDays} className="w-4 h-4" /> <FontAwesomeIcon icon={faCalendarDays} className="w-4 h-4" />
@ -214,69 +223,69 @@ export default function LinkDetails({ link }: Props) {
</div> </div>
</div> </div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<div className="flex justify-between items-center p-2 border border-sky-100 rounded-md"> <div className="flex justify-between items-center p-2 border border-sky-100 dark:border-neutral-700 rounded-md">
<div className="flex gap-2 items-center"> <div className="flex gap-2 items-center">
<div className="text-white bg-sky-300 p-2 rounded-md"> <div className="text-white bg-sky-300 dark:bg-sky-600 p-2 rounded-md">
<FontAwesomeIcon icon={faFileImage} className="w-6 h-6" /> <FontAwesomeIcon icon={faFileImage} className="w-6 h-6" />
</div> </div>
<p className="text-gray-500">Screenshot</p> <p className="text-gray-500 dark:text-white">Screenshot</p>
</div> </div>
<div className="flex text-sky-500 gap-1"> <div className="flex text-black dark:text-white gap-1">
<Link <Link
href={`/api/archives/${link.collectionId}/${link.id}.png`} href={`/api/archives/${link.collectionId}/${link.id}.png`}
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
className="cursor-pointer hover:bg-slate-200 duration-100 p-2 rounded-md" className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faArrowUpRightFromSquare} icon={faArrowUpRightFromSquare}
className="w-5 h-5" className="w-5 h-5 text-sky-500 dark:text-sky-300"
/> />
</Link> </Link>
<div <div
onClick={() => handleDownload("png")} onClick={() => handleDownload("png")}
className="cursor-pointer hover:bg-slate-200 duration-100 p-2 rounded-md" className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faCloudArrowDown} icon={faCloudArrowDown}
className="w-5 h-5 cursor-pointer" className="w-5 h-5 cursor-pointer text-sky-500 dark:text-sky-300"
/> />
</div> </div>
</div> </div>
</div> </div>
<div className="flex justify-between items-center p-2 border border-sky-100 rounded-md"> <div className="flex justify-between items-center p-2 border border-sky-100 dark:border-neutral-700 rounded-md">
<div className="flex gap-2 items-center"> <div className="flex gap-2 items-center">
<div className="text-white bg-sky-300 p-2 rounded-md"> <div className="text-white bg-sky-300 dark:bg-sky-600 p-2 rounded-md">
<FontAwesomeIcon icon={faFilePdf} className="w-6 h-6" /> <FontAwesomeIcon icon={faFilePdf} className="w-6 h-6" />
</div> </div>
<p className="text-gray-500">PDF</p> <p className="text-gray-500 dark:text-white">PDF</p>
</div> </div>
<div className="flex text-sky-500 gap-1"> <div className="flex text-black dark:text-white gap-1">
<Link <Link
href={`/api/archives/${link.collectionId}/${link.id}.pdf`} href={`/api/archives/${link.collectionId}/${link.id}.pdf`}
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
className="cursor-pointer hover:bg-slate-200 duration-100 p-2 rounded-md" className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faArrowUpRightFromSquare} icon={faArrowUpRightFromSquare}
className="w-5 h-5" className="w-5 h-5 text-sky-500 dark:text-sky-300"
/> />
</Link> </Link>
<div <div
onClick={() => handleDownload("pdf")} onClick={() => handleDownload("pdf")}
className="cursor-pointer hover:bg-slate-200 duration-100 p-2 rounded-md" className="cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-2 rounded-md"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faCloudArrowDown} icon={faCloudArrowDown}
className="w-5 h-5 cursor-pointer" className="w-5 h-5 cursor-pointer text-sky-500 dark:text-sky-300"
/> />
</div> </div>
</div> </div>

View File

@ -33,10 +33,12 @@ export default function LinkModal({
<div className={className}> <div className={className}>
<Tab.Group defaultIndex={defaultIndex}> <Tab.Group defaultIndex={defaultIndex}>
{method === "CREATE" && ( {method === "CREATE" && (
<p className="text-xl text-sky-700 text-center">New Link</p> <p className="text-xl text-black dark:text-white text-center">
New Link
</p>
)} )}
<Tab.List <Tab.List
className={`flex justify-center flex-col max-w-[15rem] sm:max-w-[30rem] mx-auto sm:flex-row gap-2 sm:gap-3 mb-5 text-sky-700 ${ className={`flex justify-center flex-col max-w-[15rem] sm:max-w-[30rem] mx-auto sm:flex-row gap-2 sm:gap-3 mb-5 text-black dark:text-white ${
isOwnerOrMod ? "" : "pb-8" isOwnerOrMod ? "" : "pb-8"
}`} }`}
> >
@ -45,8 +47,8 @@ export default function LinkModal({
<Tab <Tab
className={({ selected }) => className={({ selected }) =>
selected selected
? "px-2 py-1 bg-sky-200 duration-100 rounded-md outline-none" ? "px-2 py-1 bg-sky-200 dark:bg-sky-600 duration-100 rounded-md outline-none"
: "px-2 py-1 hover:bg-slate-200 rounded-md duration-100 outline-none" : "px-2 py-1 hover:bg-slate-200 hover:dark:bg-neutral-700 rounded-md duration-100 outline-none"
} }
> >
Link Details Link Details
@ -54,8 +56,8 @@ export default function LinkModal({
<Tab <Tab
className={({ selected }) => className={({ selected }) =>
selected selected
? "px-2 py-1 bg-sky-200 duration-100 rounded-md outline-none" ? "px-2 py-1 bg-sky-200 dark:bg-sky-600 duration-100 rounded-md outline-none"
: "px-2 py-1 hover:bg-slate-200 rounded-md duration-100 outline-none" : "px-2 py-1 hover:bg-slate-200 hover:dark:bg-neutral-700 rounded-md duration-100 outline-none"
} }
> >
Edit Link Edit Link

View File

@ -18,7 +18,7 @@ export default function PaymentPortal() {
return ( return (
<div className="mx-auto sm:w-[35rem] w-80"> <div className="mx-auto sm:w-[35rem] w-80">
<div className="max-w-[25rem] w-full mx-auto flex flex-col gap-3 justify-between"> <div className="max-w-[25rem] w-full mx-auto flex flex-col gap-3 justify-between">
<p className="text-md text-gray-500"> <p className="text-md text-gray-500 dark:text-gray-400">
To manage/cancel your subsciption, visit the billing portal. To manage/cancel your subsciption, visit the billing portal.
</p> </p>
@ -30,10 +30,13 @@ export default function PaymentPortal() {
className="mx-auto mt-2" className="mx-auto mt-2"
/> />
<p className="text-md text-gray-500"> <p className="text-md text-gray-500 dark:text-gray-400">
If you still need help or encountered any issues, feel free to reach If you still need help or encountered any issues, feel free to reach
out to us at:{" "} out to us at:{" "}
<a className="font-semibold" href="mailto:support@linkwarden.app"> <a
className="font-semibold underline"
href="mailto:support@linkwarden.app"
>
support@linkwarden.app support@linkwarden.app
</a> </a>
</p> </p>

View File

@ -81,23 +81,25 @@ export default function ChangePassword({
return ( return (
<div className="mx-auto sm:w-[35rem] w-80"> <div className="mx-auto sm:w-[35rem] w-80">
<div className="max-w-[25rem] w-full mx-auto flex flex-col gap-3 justify-between"> <div className="max-w-[25rem] w-full mx-auto flex flex-col gap-3 justify-between">
<p className="text-sm text-sky-700">New Password</p> <p className="text-sm text-black dark:text-white">New Password</p>
<input <input
value={newPassword} value={newPassword}
onChange={(e) => setNewPassword1(e.target.value)} onChange={(e) => setNewPassword1(e.target.value)}
type="password" type="password"
placeholder="••••••••••••••" placeholder="••••••••••••••"
className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-3 mx-auto dark:bg-neutral-900 border-solid border outline-none border-sky-100 dark:border-neutral-700 focus:border-sky-300 dark:focus:border-sky-600 duration-100"
/> />
<p className="text-sm text-sky-700">Confirm New Password</p> <p className="text-sm text-black dark:text-white">
Confirm New Password
</p>
<input <input
value={newPassword2} value={newPassword2}
onChange={(e) => setNewPassword2(e.target.value)} onChange={(e) => setNewPassword2(e.target.value)}
type="password" type="password"
placeholder="••••••••••••••" placeholder="••••••••••••••"
className="w-full rounded-md p-3 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-3 mx-auto dark:bg-neutral-900 border-solid border outline-none border-sky-100 dark:border-neutral-700 focus:border-sky-300 dark:focus:border-sky-600 duration-100"
/> />
<SubmitButton <SubmitButton

View File

@ -119,7 +119,9 @@ export default function PrivacySettings({
return ( return (
<div className="flex flex-col gap-3 justify-between sm:w-[35rem] w-80"> <div className="flex flex-col gap-3 justify-between sm:w-[35rem] w-80">
<div> <div>
<p className="text-sm text-sky-700 mb-2">Profile Visibility</p> <p className="text-sm text-black dark:text-white mb-2">
Profile Visibility
</p>
<Checkbox <Checkbox
label="Make profile private" label="Make profile private"
@ -128,19 +130,21 @@ export default function PrivacySettings({
onClick={() => setUser({ ...user, isPrivate: !user.isPrivate })} onClick={() => setUser({ ...user, isPrivate: !user.isPrivate })}
/> />
<p className="text-gray-500 text-sm"> <p className="text-gray-500 dark:text-gray-300 text-sm">
This will limit who can find and add you to other Collections. This will limit who can find and add you to other Collections.
</p> </p>
{user.isPrivate && ( {user.isPrivate && (
<div> <div>
<p className="text-sm text-sky-700 my-2">Whitelisted Users</p> <p className="text-sm text-black dark:text-white mt-2">
<p className="text-gray-500 text-sm mb-3"> Whitelisted Users
</p>
<p className="text-gray-500 dark:text-gray-300 text-sm mb-3">
Please provide the Username of the users you wish to grant Please provide the Username of the users you wish to grant
visibility to your profile. Separated by comma. visibility to your profile. Separated by comma.
</p> </p>
<textarea <textarea
className="w-full resize-none border rounded-md duration-100 bg-white p-2 outline-none border-sky-100 focus:border-sky-700" className="w-full resize-none border rounded-md duration-100 bg-white dark:bg-neutral-900 p-2 outline-none border-sky-100 dark:border-neutral-700 focus:border-sky-300 dark:focus:border-sky-600"
placeholder="Your profile is hidden from everyone right now..." placeholder="Your profile is hidden from everyone right now..."
value={whitelistedUsersTextbox} value={whitelistedUsersTextbox}
onChange={(e) => { onChange={(e) => {
@ -152,7 +156,9 @@ export default function PrivacySettings({
</div> </div>
<div className="mt-5"> <div className="mt-5">
<p className="text-sm text-sky-700 mb-2">Import/Export Data</p> <p className="text-sm text-black dark:text-white mb-2">
Import/Export Data
</p>
<div className="flex gap-2"> <div className="flex gap-2">
<div <div
@ -162,7 +168,7 @@ export default function PrivacySettings({
> >
<div <div
id="import-dropdown" id="import-dropdown"
className="border border-slate-200 rounded-md bg-white px-2 text-center select-none cursor-pointer text-sky-900 duration-100 hover:border-sky-700" className="border border-slate-200 dark:border-neutral-700 rounded-md bg-white dark:bg-neutral-800 px-2 text-center select-none cursor-pointer duration-100 hover:border-sky-300 hover:dark:border-sky-600"
> >
Import From Import From
</div> </div>
@ -172,13 +178,13 @@ export default function PrivacySettings({
const target = e.target as HTMLInputElement; const target = e.target as HTMLInputElement;
if (target.id !== "import-dropdown") setImportDropdown(false); if (target.id !== "import-dropdown") setImportDropdown(false);
}} }}
className={`absolute top-7 left-0 w-36 py-1 shadow-md border border-sky-100 bg-gray-50 rounded-md flex flex-col z-20`} className={`absolute top-7 left-0 w-36 py-1 shadow-md border border-sky-100 dark:border-neutral-700 bg-gray-50 dark:bg-neutral-800 rounded-md flex flex-col z-20`}
> >
<div className="cursor-pointer rounded-md"> <div className="cursor-pointer rounded-md">
<label <label
htmlFor="import-file" htmlFor="import-file"
title="JSON" title="JSON"
className="flex items-center gap-2 py-1 px-2 hover:bg-slate-200 duration-100 cursor-pointer" className="flex items-center gap-2 py-1 px-2 hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 cursor-pointer"
> >
Linkwarden Linkwarden
<input <input
@ -196,7 +202,7 @@ export default function PrivacySettings({
</div> </div>
<Link className="w-fit" href="/api/data"> <Link className="w-fit" href="/api/data">
<div className="border border-slate-200 rounded-md bg-white px-2 text-center select-none cursor-pointer text-sky-900 duration-100 hover:border-sky-700"> <div className="border border-slate-200 dark:border-neutral-700 rounded-md bg-white dark:bg-neutral-800 px-2 text-center select-none cursor-pointer duration-100 hover:border-sky-300 hover:dark:border-sky-600">
Export Data Export Data
</div> </div>
</Link> </Link>

View File

@ -102,7 +102,9 @@ export default function ProfileSettings({
<div className="flex flex-col gap-3 justify-between sm:w-[35rem] w-80"> <div className="flex flex-col gap-3 justify-between sm:w-[35rem] w-80">
<div className="grid sm:grid-cols-2 gap-3 auto-rows-auto"> <div className="grid sm:grid-cols-2 gap-3 auto-rows-auto">
<div className="sm:row-span-2 sm:justify-self-center mx-auto mb-3"> <div className="sm:row-span-2 sm:justify-self-center mx-auto mb-3">
<p className="text-sm text-sky-700 mb-2 text-center">Profile Photo</p> <p className="text-sm text-black dark:text-white mb-2 text-center">
Profile Photo
</p>
<div className="w-28 h-28 flex items-center justify-center rounded-full relative"> <div className="w-28 h-28 flex items-center justify-center rounded-full relative">
<ProfilePhoto <ProfilePhoto
src={user.profilePic} src={user.profilePic}
@ -127,7 +129,7 @@ export default function ProfileSettings({
<label <label
htmlFor="upload-photo" htmlFor="upload-photo"
title="PNG or JPG (Max: 3MB)" title="PNG or JPG (Max: 3MB)"
className="border border-slate-200 rounded-md bg-white px-2 text-center select-none cursor-pointer text-sky-900 duration-100 hover:border-sky-700" className="border border-slate-200 dark:border-neutral-700 rounded-md bg-white dark:bg-neutral-800 px-2 text-center select-none cursor-pointer duration-100 hover:border-sky-300 hover:dark:border-sky-600"
> >
Browse... Browse...
<input <input
@ -145,28 +147,30 @@ export default function ProfileSettings({
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
<div> <div>
<p className="text-sm text-sky-700 mb-2">Display Name</p> <p className="text-sm text-black dark:text-white mb-2">
Display Name
</p>
<input <input
type="text" type="text"
value={user.name} value={user.name}
onChange={(e) => setUser({ ...user, name: e.target.value })} onChange={(e) => setUser({ ...user, name: e.target.value })}
className="w-full rounded-md p-2 border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-2 border-sky-100 dark:border-neutral-700 dark:bg-neutral-900 border-solid border outline-none focus:border-sky-700 focus:dark:border-sky-600 duration-100"
/> />
</div> </div>
<div> <div>
<p className="text-sm text-sky-700 mb-2">Username</p> <p className="text-sm text-black dark:text-white mb-2">Username</p>
<input <input
type="text" type="text"
value={user.username || ""} value={user.username || ""}
onChange={(e) => setUser({ ...user, username: e.target.value })} onChange={(e) => setUser({ ...user, username: e.target.value })}
className="w-full rounded-md p-2 border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-2 border-sky-100 dark:border-neutral-700 dark:bg-neutral-900 border-solid border outline-none focus:border-sky-700 focus:dark:border-sky-600 duration-100"
/> />
</div> </div>
{emailEnabled ? ( {emailEnabled ? (
<div> <div>
<p className="text-sm text-sky-700 mb-2">Email</p> <p className="text-sm text-black mb-2">Email</p>
<input <input
type="text" type="text"
value={user.email || ""} value={user.email || ""}
@ -186,10 +190,10 @@ export default function ProfileSettings({
{/* <hr /> TODO: Export functionality {/* <hr /> TODO: Export functionality
<p className="text-sky-700">Data Settings</p> <p className="text-black">Data Settings</p>
<div className="w-fit"> <div className="w-fit">
<div className="border border-sky-100 rounded-md bg-white px-2 py-1 text-center select-none cursor-pointer text-sky-900 duration-100 hover:border-sky-700"> <div className="border border-sky-100 rounded-md bg-white px-2 py-1 text-center select-none cursor-pointer text-black duration-100 hover:border-sky-700">
Export Data Export Data
</div> </div>
</div> */} </div> */}

View File

@ -27,12 +27,12 @@ export default function UserModal({
return ( return (
<div className={className}> <div className={className}>
<Tab.Group defaultIndex={defaultIndex}> <Tab.Group defaultIndex={defaultIndex}>
<Tab.List className="flex justify-center flex-col max-w-[15rem] sm:max-w-[30rem] mx-auto sm:flex-row gap-2 sm:gap-3 mb-5 text-sky-700"> <Tab.List className="flex justify-center flex-col max-w-[15rem] sm:max-w-[30rem] mx-auto sm:flex-row gap-2 sm:gap-3 mb-5 text-black dark:text-white">
<Tab <Tab
className={({ selected }) => className={({ selected }) =>
selected selected
? "px-2 py-1 bg-sky-200 duration-100 rounded-md outline-none" ? "px-2 py-1 bg-sky-200 dark:bg-sky-500 dark:text-white duration-100 rounded-md outline-none"
: "px-2 py-1 hover:bg-slate-200 rounded-md duration-100 outline-none" : "px-2 py-1 hover:bg-slate-200 hover:dark:bg-neutral-700 rounded-md duration-100 outline-none"
} }
> >
Profile Settings Profile Settings
@ -41,8 +41,8 @@ export default function UserModal({
<Tab <Tab
className={({ selected }) => className={({ selected }) =>
selected selected
? "px-2 py-1 bg-sky-200 duration-100 rounded-md outline-none" ? "px-2 py-1 bg-sky-200 dark:bg-sky-500 dark:text-white duration-100 rounded-md outline-none"
: "px-2 py-1 hover:bg-slate-200 rounded-md duration-100 outline-none" : "px-2 py-1 hover:bg-slate-200 hover:dark:bg-neutral-700 rounded-md duration-100 outline-none"
} }
> >
Privacy Settings Privacy Settings
@ -51,8 +51,8 @@ export default function UserModal({
<Tab <Tab
className={({ selected }) => className={({ selected }) =>
selected selected
? "px-2 py-1 bg-sky-200 duration-100 rounded-md outline-none" ? "px-2 py-1 bg-sky-200 dark:bg-sky-500 dark:text-white duration-100 rounded-md outline-none"
: "px-2 py-1 hover:bg-slate-200 rounded-md duration-100 outline-none" : "px-2 py-1 hover:bg-slate-200 hover:dark:bg-neutral-700 rounded-md duration-100 outline-none"
} }
> >
Password Password
@ -62,8 +62,8 @@ export default function UserModal({
<Tab <Tab
className={({ selected }) => className={({ selected }) =>
selected selected
? "px-2 py-1 bg-sky-200 duration-100 rounded-md outline-none" ? "px-2 py-1 bg-sky-200 dark:bg-sky-500 duration-100 rounded-md outline-none"
: "px-2 py-1 hover:bg-slate-200 rounded-md duration-100 outline-none" : "px-2 py-1 hover:bg-slate-200 hover:dark:bg-neutral-700 rounded-md duration-100 outline-none"
} }
> >
Billing Portal Billing Portal

View File

@ -16,14 +16,14 @@ export default function Modal({ toggleModal, className, children }: Props) {
onClickOutside={toggleModal} onClickOutside={toggleModal}
className={`m-auto ${className}`} className={`m-auto ${className}`}
> >
<div className="slide-up relative border-sky-100 rounded-2xl border-solid border shadow-lg p-5 bg-white"> <div className="slide-up relative border-sky-100 dark:border-neutral-700 rounded-2xl border-solid border shadow-lg p-5 bg-white dark:bg-neutral-900">
<div <div
onClick={toggleModal as MouseEventHandler<HTMLDivElement>} onClick={toggleModal as MouseEventHandler<HTMLDivElement>}
className="absolute top-5 left-5 inline-flex rounded-md cursor-pointer hover:bg-slate-200 duration-100 z-20 p-2" className="absolute top-5 left-5 inline-flex rounded-md cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 z-20 p-2"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faChevronLeft} icon={faChevronLeft}
className="w-4 h-4 text-gray-500" className="w-4 h-4 text-gray-500 dark:text-gray-200"
/> />
</div> </div>
{children} {children}

View File

@ -10,6 +10,7 @@ import Search from "@/components/Search";
import useAccountStore from "@/store/account"; import useAccountStore from "@/store/account";
import ProfilePhoto from "@/components/ProfilePhoto"; import ProfilePhoto from "@/components/ProfilePhoto";
import useModalStore from "@/store/modals"; import useModalStore from "@/store/modals";
import { useTheme } from "next-themes";
export default function Navbar() { export default function Navbar() {
const { setModal } = useModalStore(); const { setModal } = useModalStore();
@ -22,6 +23,16 @@ export default function Navbar() {
const router = useRouter(); const router = useRouter();
const { theme, setTheme } = useTheme();
const handleToggle = () => {
if (theme === "dark") {
setTheme("light");
} else {
setTheme("dark");
}
};
window.addEventListener("resize", () => setSidebar(false)); window.addEventListener("resize", () => setSidebar(false));
useEffect(() => { useEffect(() => {
@ -33,10 +44,10 @@ export default function Navbar() {
}; };
return ( return (
<div className="flex justify-between gap-2 items-center px-5 py-2 border-solid border-b-sky-100 border-b h-16"> <div className="flex justify-between gap-2 items-center px-5 py-2 border-solid border-b-sky-100 dark:border-b-neutral-700 border-b h-16">
<div <div
onClick={toggleSidebar} onClick={toggleSidebar}
className="inline-flex lg:hidden gap-1 items-center select-none cursor-pointer p-[0.687rem] text-sky-700 rounded-md duration-100 hover:bg-slate-200" className="inline-flex lg:hidden gap-1 items-center select-none cursor-pointer p-[0.687rem] text-black dark:text-white rounded-md duration-100 hover:bg-slate-200 dark:hover:bg-neutral-700"
> >
<FontAwesomeIcon icon={faBars} className="w-5 h-5" /> <FontAwesomeIcon icon={faBars} className="w-5 h-5" />
</div> </div>
@ -50,7 +61,7 @@ export default function Navbar() {
method: "CREATE", method: "CREATE",
}); });
}} }}
className="inline-flex gap-1 relative sm:w-[7.2rem] items-center font-semibold select-none cursor-pointer p-[0.687rem] sm:p-2 sm:px-3 rounded-md sm:rounded-full hover:bg-sky-100 text-sky-700 sm:text-white sm:bg-sky-700 sm:hover:bg-sky-600 duration-100 group" className="inline-flex gap-1 relative sm:w-[7.2rem] items-center font-semibold select-none cursor-pointer p-[0.687rem] sm:p-2 sm:px-3 rounded-md sm:rounded-full hover:bg-sky-100 dark:hover:bg-sky-800 sm:dark:hover:bg-sky-600 text-sky-500 sm:text-white sm:bg-sky-700 sm:hover:bg-sky-600 duration-100 group"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faPlus} icon={faPlus}
@ -60,20 +71,19 @@ export default function Navbar() {
New Link New Link
</span> </span>
</div> </div>
<div className="relative"> <div className="relative">
<div <div
className="flex gap-1 group sm:hover:bg-slate-200 sm:hover:p-1 sm:hover:pr-2 duration-100 h-10 rounded-full items-center w-fit bg-white cursor-pointer" className="flex gap-1 group sm:hover:bg-slate-200 sm:hover:dark:bg-neutral-700 sm:hover:p-1 sm:hover:pr-2 duration-100 h-10 rounded-full items-center w-fit cursor-pointer"
onClick={() => setProfileDropdown(!profileDropdown)} onClick={() => setProfileDropdown(!profileDropdown)}
id="profile-dropdown" id="profile-dropdown"
> >
<ProfilePhoto <ProfilePhoto
src={account.profilePic} src={account.profilePic}
className="sm:group-hover:h-8 sm:group-hover:w-8 duration-100 border-[3px]" className="sm:group-hover:h-8 sm:group-hover:w-8 duration-100 border-[3px]"
/> />
<p <p
id="profile-dropdown" id="profile-dropdown"
className="font-bold text-sky-700 leading-3 hidden sm:block select-none truncate max-w-[8rem] py-1" className="font-bold text-black dark:text-white leading-3 hidden sm:block select-none truncate max-w-[8rem] py-1"
> >
{account.name} {account.name}
</p> </p>
@ -92,6 +102,13 @@ export default function Navbar() {
setProfileDropdown(!profileDropdown); setProfileDropdown(!profileDropdown);
}, },
}, },
{
name: `Switch to ${theme === "light" ? "Dark" : "Light"}`,
onClick: () => {
handleToggle();
setProfileDropdown(!profileDropdown);
},
},
{ {
name: "Logout", name: "Logout",
onClick: () => { onClick: () => {

View File

@ -7,12 +7,12 @@ export default function NoLinksFound() {
const { setModal } = useModalStore(); const { setModal } = useModalStore();
return ( return (
<div className="border border-solid border-sky-100 w-full p-10 rounded-2xl"> <div className="border border-solid border-sky-100 dark:border-neutral-700 w-full p-10 rounded-2xl">
<p className="text-center text-3xl text-sky-700"> <p className="text-center text-3xl text-black dark:text-white">
You haven&apos;t created any Links Here You haven&apos;t created any Links Here
</p> </p>
<br /> <br />
<div className="text-center text-sky-900 text-sm flex items-baseline justify-center gap-1 w-full"> <div className="text-center text-black dark:text-white text-sm flex items-baseline justify-center gap-1 w-full">
<p>Start by creating a</p>{" "} <p>Start by creating a</p>{" "}
<div <div
onClick={() => { onClick={() => {
@ -22,7 +22,7 @@ export default function NoLinksFound() {
method: "CREATE", method: "CREATE",
}); });
}} }}
className="inline-flex gap-1 relative w-[7.2rem] items-center font-semibold select-none cursor-pointer p-2 px-3 rounded-full text-white bg-sky-700 hover:bg-sky-600 duration-100 group" className="inline-flex gap-1 relative w-[7.2rem] items-center font-semibold select-none cursor-pointer p-2 px-3 rounded-full text-white bg-sky-700 dark:bg-sky-400 hover:bg-sky-600 duration-100 group"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faPlus} icon={faPlus}

View File

@ -33,7 +33,7 @@ export default function ProfilePhoto({
return error || !src ? ( return error || !src ? (
<div <div
className={`bg-sky-500 text-white h-10 w-10 aspect-square shadow rounded-full border border-slate-200 flex items-center justify-center ${className}`} className={`bg-sky-600 dark:bg-sky-600 text-white h-10 w-10 aspect-square shadow rounded-full border border-slate-200 dark:border-neutral-700 flex items-center justify-center ${className}`}
> >
<FontAwesomeIcon icon={faUser} className="w-1/2 h-1/2 aspect-square" /> <FontAwesomeIcon icon={faUser} className="w-1/2 h-1/2 aspect-square" />
</div> </div>
@ -43,7 +43,7 @@ export default function ProfilePhoto({
src={src} src={src}
height={112} height={112}
width={112} width={112}
className={`h-10 w-10 shadow rounded-full aspect-square border border-slate-200 ${className}`} className={`h-10 w-10 shadow rounded-full aspect-square border border-slate-200 dark:border-neutral-700 ${className}`}
/> />
); );
} }

View File

@ -58,8 +58,10 @@ export default function LinkCard({ link, count }: Props) {
<div className="flex justify-between items-center gap-5 w-full h-full z-0"> <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 flex-col justify-between">
<div className="flex items-baseline gap-1"> <div className="flex items-baseline gap-1">
<p className="text-sm text-sky-500 font-bold">{count + 1}.</p> <p className="text-xs text-gray-500">{count + 1}</p>
<p className="text-lg text-sky-700 font-bold">{link.name}</p> <p className="text-lg text-black">
{link.name || link.description}
</p>
</div> </div>
<p className="text-gray-500 text-sm font-medium"> <p className="text-gray-500 text-sm font-medium">
@ -70,7 +72,7 @@ export default function LinkCard({ link, count }: Props) {
{link.tags.map((e, i) => ( {link.tags.map((e, i) => (
<p <p
key={i} key={i}
className="px-2 py-1 bg-sky-200 text-sky-700 text-xs rounded-3xl cursor-pointer truncate max-w-[10rem]" className="px-2 py-1 bg-sky-200 text-black text-xs rounded-3xl cursor-pointer truncate max-w-[10rem]"
> >
{e.name} {e.name}
</p> </p>
@ -79,7 +81,7 @@ export default function LinkCard({ link, count }: Props) {
</div> </div>
<div className="flex gap-2 items-center flex-wrap mt-2"> <div className="flex gap-2 items-center flex-wrap mt-2">
<p className="text-gray-500">{formattedDate}</p> <p className="text-gray-500">{formattedDate}</p>
<div className="text-sky-500 font-bold flex items-center gap-1"> <div className="text-black flex items-center gap-1">
<p>{url ? url.host : link.url}</p> <p>{url ? url.host : link.url}</p>
</div> </div>
</div> </div>

View File

@ -20,13 +20,15 @@ export default function RadioButton({ label, state, onClick }: Props) {
/> />
<FontAwesomeIcon <FontAwesomeIcon
icon={faCircleCheck} icon={faCircleCheck}
className="w-5 h-5 text-sky-700 peer-checked:block hidden" className="w-5 h-5 text-sky-500 dark:text-sky-300 peer-checked:block hidden"
/> />
<FontAwesomeIcon <FontAwesomeIcon
icon={faCircle} icon={faCircle}
className="w-5 h-5 text-sky-700 peer-checked:hidden block" className="w-5 h-5 text-sky-500 dark:text-sky-300 peer-checked:hidden block"
/> />
<span className="text-sky-900 rounded select-none">{label}</span> <span className="text-black dark:text-white rounded select-none">
{label}
</span>
</label> </label>
); );
} }

View File

@ -1,6 +1,9 @@
export default function RequiredBadge() { export default function RequiredBadge() {
return ( return (
<span title="Required Field" className="text-sky-700 cursor-help"> <span
title="Required Field"
className="text-black dark:text-white cursor-help"
>
{" "} {" "}
* *
</span> </span>

View File

@ -24,7 +24,7 @@ export default function Search() {
> >
<label <label
htmlFor="search-box" htmlFor="search-box"
className="inline-flex w-fit absolute left-2 pointer-events-none rounded-md p-1 text-sky-500 group-hover:text-sky-700" className="inline-flex w-fit absolute left-2 pointer-events-none rounded-md p-1 text-sky-500 dark:text-sky-300"
> >
<FontAwesomeIcon icon={faMagnifyingGlass} className="w-5 h-5" /> <FontAwesomeIcon icon={faMagnifyingGlass} className="w-5 h-5" />
</label> </label>
@ -44,7 +44,7 @@ export default function Search() {
router.push("/search/" + encodeURIComponent(searchQuery)) router.push("/search/" + encodeURIComponent(searchQuery))
} }
autoFocus={searchBox} autoFocus={searchBox}
className="border border-sky-100 rounded-md pl-10 py-2 pr-2 w-44 sm:w-60 focus:border-sky-700 md:focus:w-80 hover:border-sky-700 duration-100 outline-none" className="border border-sky-100 dark:border-neutral-700 focus:border-sky-300 dark:focus:border-sky-600 rounded-md pl-10 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 bg-inherit"
/> />
</div> </div>
); );

View File

@ -51,22 +51,23 @@ export default function Sidebar({ className }: { className?: string }) {
return ( return (
<div <div
className={`bg-gray-100 h-full w-64 xl:w-80 overflow-y-auto border-solid border-r-sky-100 px-2 border z-20 ${className}`} className={`bg-gray-100 dark:bg-neutral-800 h-full w-64 xl:w-80 overflow-y-auto border-solid border dark:border-neutral-800 border-r-sky-100 dark:border-r-neutral-700 px-2 z-20 ${className}`}
> >
<div className="flex justify-center gap-2 mt-2"> <div className="flex justify-center gap-2 mt-2">
<Link <Link
href="/dashboard" href="/dashboard"
className={`${ className={`${
active === "/dashboard" active === "/dashboard"
? "bg-sky-200" ? "bg-sky-200 dark:bg-sky-600"
: "hover:bg-slate-200 bg-gray-100" : "hover:bg-slate-200 hover:dark:bg-neutral-700"
} outline-sky-100 outline-1 duration-100 py-1 px-2 rounded-md cursor-pointer flex justify-center flex-col items-center gap-1 w-full`} } outline-sky-100 outline-1 duration-100 py-1 px-2 rounded-md cursor-pointer flex justify-center flex-col items-center gap-1 w-full`}
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faChartSimple} icon={faChartSimple}
className={`w-8 h-8 drop-shadow text-sky-500`} className={`w-8 h-8 drop-shadow text-sky-500 dark:text-sky-300`}
/> />
<p className="text-sky-700 text-xs xl:text-sm font-semibold">
<p className="text-black dark:text-white text-xs xl:text-sm font-semibold">
Dashboard Dashboard
</p> </p>
</Link> </Link>
@ -75,28 +76,34 @@ export default function Sidebar({ className }: { className?: string }) {
href="/links" href="/links"
className={`${ className={`${
active === "/links" active === "/links"
? "bg-sky-200" ? "bg-sky-200 dark:bg-sky-600"
: "hover:bg-slate-200 bg-gray-100" : "hover:bg-slate-200 hover:dark:bg-neutral-700"
} outline-sky-100 outline-1 duration-100 py-1 px-2 rounded-md cursor-pointer flex justify-center flex-col items-center gap-1 w-full`} } outline-sky-100 outline-1 duration-100 py-1 px-2 rounded-md cursor-pointer flex justify-center flex-col items-center gap-1 w-full`}
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faLink} icon={faLink}
className={`w-8 h-8 drop-shadow text-sky-500`} className={`w-8 h-8 drop-shadow text-sky-500 dark:text-sky-300`}
/> />
<p className="text-sky-700 text-xs xl:text-sm font-semibold">Links</p>
<p className="text-black dark:text-white text-xs xl:text-sm font-semibold">
Links
</p>
</Link> </Link>
<Link <Link
href="/collections" href="/collections"
className={`${ className={`${
active === "/collections" ? "bg-sky-200" : "hover:bg-slate-200" active === "/collections"
? "bg-sky-200 dark:bg-sky-600"
: "hover:bg-slate-200 hover:dark:bg-neutral-700"
} outline-sky-100 outline-1 duration-100 py-1 px-2 rounded-md cursor-pointer flex justify-center flex-col items-center gap-1 w-full`} } outline-sky-100 outline-1 duration-100 py-1 px-2 rounded-md cursor-pointer flex justify-center flex-col items-center gap-1 w-full`}
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faFolder} icon={faFolder}
className={`w-8 h-8 drop-shadow text-sky-500`} className={`w-8 h-8 drop-shadow text-sky-500 dark:text-sky-300`}
/> />
<p className="text-sky-700 text-xs xl:text-sm font-semibold">
<p className="text-black dark:text-white text-xs xl:text-sm font-semibold">
Collections Collections
</p> </p>
</Link> </Link>
@ -107,7 +114,7 @@ export default function Sidebar({ className }: { className?: string }) {
onClick={() => { onClick={() => {
setCollectionDisclosure(!collectionDisclosure); setCollectionDisclosure(!collectionDisclosure);
}} }}
className="flex items-center justify-between text-sm w-full text-left mb-2 pl-2 font-bold text-gray-500 mt-5" className="flex items-center justify-between text-sm w-full text-left mb-2 pl-2 font-bold text-gray-500 dark:text-white mt-5"
> >
<p>Collections</p> <p>Collections</p>
@ -136,8 +143,8 @@ export default function Sidebar({ className }: { className?: string }) {
<div <div
className={`${ className={`${
active === `/collections/${e.id}` active === `/collections/${e.id}`
? "bg-sky-200" ? "bg-sky-200 dark:bg-sky-700 "
: "hover:bg-slate-200 bg-gray-100" : "hover:bg-slate-200 hover:dark:bg-neutral-700"
} duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`} } duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8 capitalize`}
> >
<FontAwesomeIcon <FontAwesomeIcon
@ -146,7 +153,7 @@ export default function Sidebar({ className }: { className?: string }) {
style={{ color: e.color }} style={{ color: e.color }}
/> />
<p className="text-sky-700 truncate w-full pr-7"> <p className="text-black dark:text-white truncate w-full pr-7">
{e.name} {e.name}
</p> </p>
</div> </div>
@ -157,7 +164,7 @@ export default function Sidebar({ className }: { className?: string }) {
<div <div
className={`duration-100 py-1 px-2 flex items-center gap-2 w-full rounded-md h-8 capitalize`} className={`duration-100 py-1 px-2 flex items-center gap-2 w-full rounded-md h-8 capitalize`}
> >
<p className="text-gray-500 text-xs font-semibold truncate w-full pr-7"> <p className="text-gray-500 dark:text-white text-xs font-semibold truncate w-full pr-7">
You Have No Collections... You Have No Collections...
</p> </p>
</div> </div>
@ -170,7 +177,7 @@ export default function Sidebar({ className }: { className?: string }) {
onClick={() => { onClick={() => {
setTagDisclosure(!tagDisclosure); setTagDisclosure(!tagDisclosure);
}} }}
className="flex items-center justify-between text-sm w-full text-left mb-2 pl-2 font-bold text-gray-500 mt-5" className="flex items-center justify-between text-sm w-full text-left mb-2 pl-2 font-bold text-gray-500 dark:text-white mt-5"
> >
<p>Tags</p> <p>Tags</p>
<FontAwesomeIcon <FontAwesomeIcon
@ -196,16 +203,16 @@ export default function Sidebar({ className }: { className?: string }) {
<div <div
className={`${ className={`${
active === `/tags/${e.id}` active === `/tags/${e.id}`
? "bg-sky-200" ? "bg-sky-200 dark:bg-sky-700"
: "hover:bg-slate-200 bg-gray-100" : "hover:bg-slate-200 hover:dark:bg-neutral-700"
} duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`} } duration-100 py-1 px-2 cursor-pointer flex items-center gap-2 w-full rounded-md h-8`}
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faHashtag} icon={faHashtag}
className="w-4 h-4 text-sky-500 mt-1" className="w-4 h-4 text-sky-500 dark:text-sky-300 mt-1"
/> />
<p className="text-sky-700 truncate w-full pr-7"> <p className="text-black dark:text-white truncate w-full pr-7">
{e.name} {e.name}
</p> </p>
</div> </div>
@ -216,7 +223,7 @@ export default function Sidebar({ className }: { className?: string }) {
<div <div
className={`duration-100 py-1 px-2 flex items-center gap-2 w-full rounded-md h-8 capitalize`} className={`duration-100 py-1 px-2 flex items-center gap-2 w-full rounded-md h-8 capitalize`}
> >
<p className="text-gray-500 text-xs font-semibold truncate w-full pr-7"> <p className="text-gray-500 dark:text-white text-xs font-semibold truncate w-full pr-7">
You Have No Tags... You Have No Tags...
</p> </p>
</div> </div>

View File

@ -21,9 +21,11 @@ export default function SortDropdown({
const target = e.target as HTMLInputElement; const target = e.target as HTMLInputElement;
if (target.id !== "sort-dropdown") toggleSortDropdown(); if (target.id !== "sort-dropdown") toggleSortDropdown();
}} }}
className="absolute top-8 right-0 border border-sky-100 shadow-md bg-gray-50 rounded-md p-2 z-20 w-48" className="absolute top-8 right-0 border border-sky-100 dark:border-neutral-700 shadow-md bg-gray-50 dark:bg-neutral-800 rounded-md p-2 z-20 w-48"
> >
<p className="mb-2 text-sky-900 text-center font-semibold">Sort by</p> <p className="mb-2 text-black dark:text-white text-center font-semibold">
Sort by
</p>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<RadioButton <RadioButton
label="Date (Newest First)" label="Date (Newest First)"

View File

@ -0,0 +1,29 @@
import { useTheme } from "next-themes";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faSun, faMoon } from "@fortawesome/free-solid-svg-icons";
export default function ToggleDarkMode() {
const { theme, setTheme } = useTheme();
const handleToggle = () => {
if (theme === "dark") {
setTheme("light");
} else {
setTheme("dark");
}
};
return (
<div
className="flex gap-1 duration-100 h-10 rounded-full items-center w-fit cursor-pointer"
onClick={handleToggle}
>
<div className="shadow bg-sky-700 dark:bg-sky-400 flex items-center justify-center rounded-full text-white w-10 h-10 duration-100">
<FontAwesomeIcon
icon={theme === "dark" ? faSun : faMoon}
className="w-1/2 h-1/2"
/>
</div>
</div>
);
}

View File

@ -18,12 +18,12 @@ export default function CenteredForm({ text, children }: Props) {
className="h-12 w-fit mx-auto" className="h-12 w-fit mx-auto"
/> />
{text ? ( {text ? (
<p className="text-lg sm:w-[30rem] w-80 mx-auto font-semibold text-black px-2 text-center"> <p className="text-lg sm:w-[30rem] w-80 mx-auto font-semibold text-black dark:text-white px-2 text-center">
{text} {text}
</p> </p>
) : undefined} ) : undefined}
{children} {children}
<p className="text-center text-xs text-gray-500"> <p className="text-center text-xs text-gray-500 dark:text-gray-400">
© {new Date().getFullYear()} Linkwarden. All rights reserved. © {new Date().getFullYear()} Linkwarden. All rights reserved.
</p> </p>
</div> </div>

View File

@ -36,6 +36,7 @@
"eslint-config-next": "13.4.9", "eslint-config-next": "13.4.9",
"next": "13.4.12", "next": "13.4.12",
"next-auth": "^4.22.1", "next-auth": "^4.22.1",
"next-themes": "^0.2.1",
"nodemailer": "^6.9.3", "nodemailer": "^6.9.3",
"playwright": "^1.35.1", "playwright": "^1.35.1",
"react": "18.2.0", "react": "18.2.0",

View File

@ -1,4 +1,4 @@
import React from "react"; import React, { useEffect } from "react";
import "@/styles/globals.css"; import "@/styles/globals.css";
import { SessionProvider } from "next-auth/react"; import { SessionProvider } from "next-auth/react";
import type { AppProps } from "next/app"; import type { AppProps } from "next/app";
@ -6,6 +6,7 @@ import Head from "next/head";
import AuthRedirect from "@/layouts/AuthRedirect"; import AuthRedirect from "@/layouts/AuthRedirect";
import { Toaster } from "react-hot-toast"; import { Toaster } from "react-hot-toast";
import { Session } from "next-auth"; import { Session } from "next-auth";
import { ThemeProvider } from "next-themes";
export default function App({ export default function App({
Component, Component,
@ -13,6 +14,10 @@ export default function App({
}: AppProps<{ }: AppProps<{
session: Session; session: Session;
}>) { }>) {
useEffect(() => {
if (!localStorage.getItem("theme")) localStorage.setItem("theme", "light");
}, []);
return ( return (
<SessionProvider session={pageProps.session}> <SessionProvider session={pageProps.session}>
<Head> <Head>
@ -37,13 +42,18 @@ export default function App({
/> />
<link rel="manifest" href="/site.webmanifest" /> <link rel="manifest" href="/site.webmanifest" />
</Head> </Head>
<Toaster
position="top-center"
reverseOrder={false}
toastOptions={{ className: "border border-sky-100" }}
/>
<AuthRedirect> <AuthRedirect>
<Component {...pageProps} /> <ThemeProvider attribute="class">
<Toaster
position="top-center"
reverseOrder={false}
toastOptions={{
className:
"border border-sky-100 dark:dark:border-neutral-700 dark:bg-neutral-900 dark:text-white",
}}
/>
<Component {...pageProps} />
</ThemeProvider>
</AuthRedirect> </AuthRedirect>
</SessionProvider> </SessionProvider>
); );

View File

@ -39,13 +39,13 @@ export default function Subscribe() {
return ( return (
<CenteredForm> <CenteredForm>
<div className="p-2 mx-auto flex flex-col gap-3 justify-between sm:w-[30rem] w-80 bg-slate-50 rounded-2xl shadow-md border border-sky-100"> <div className="p-4 mx-auto flex flex-col gap-3 justify-between sm:w-[30rem] w-80 bg-slate-50 dark:border-neutral-700 dark:bg-neutral-800 rounded-2xl shadow-md border border-sky-100">
<p className="text-2xl text-center text-black font-bold"> <p className="text-2xl text-center text-black dark:text-white font-bold">
Choose a Username (Last step) Choose a Username (Last step)
</p> </p>
<div> <div>
<p className="text-sm text-sky-700 w-fit font-semibold mb-1"> <p className="text-sm text-black dark:text-white w-fit font-semibold mb-1">
Username Username
</p> </p>
@ -54,13 +54,16 @@ export default function Subscribe() {
placeholder="john" placeholder="john"
value={inputedUsername} value={inputedUsername}
onChange={(e) => setInputedUsername(e.target.value)} onChange={(e) => setInputedUsername(e.target.value)}
className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-700 dark:focus:border-sky-600 dark:border-neutral-700 dark:bg-neutral-900 duration-100"
/> />
</div> </div>
<div> <div>
<p className="text-md text-gray-500 mt-1"> <p className="text-md text-gray-500 dark:text-gray-400 mt-1">
Feel free to reach out to us at{" "} Feel free to reach out to us at{" "}
<a className="font-semibold" href="mailto:support@linkwarden.app"> <a
className="font-semibold underline"
href="mailto:support@linkwarden.app"
>
support@linkwarden.app support@linkwarden.app
</a>{" "} </a>{" "}
in case of any issues. in case of any issues.
@ -76,7 +79,7 @@ export default function Subscribe() {
<div <div
onClick={() => signOut()} onClick={() => signOut()}
className="w-fit mx-auto cursor-pointer text-gray-500 font-semibold " className="w-fit mx-auto cursor-pointer text-gray-500 dark:text-gray-400 font-semibold "
> >
Sign Out Sign Out
</div> </div>

View File

@ -50,7 +50,7 @@ export default function Index() {
return ( return (
<MainLayout> <MainLayout>
<div className="p-5 flex flex-col gap-5 w-full"> <div className="p-5 flex flex-col gap-5 w-full">
<div className="bg-gradient-to-tr from-sky-100 from-10% via-gray-100 via-20% rounded-2xl shadow min-h-[10rem] p-5 flex gap-5 flex-col justify-between"> <div className="bg-gradient-to-tr from-sky-100 dark:from-gray-800 from-10% via-gray-100 via-20% to-white dark:to-neutral-800 to-100% rounded-2xl shadow min-h-[10rem] p-5 flex gap-5 flex-col justify-between">
<div className="flex flex-col sm:flex-row gap-3 justify-between items-center sm:items-start"> <div className="flex flex-col sm:flex-row gap-3 justify-between items-center sm:items-start">
{activeCollection && ( {activeCollection && (
<div className="flex gap-3 items-center"> <div className="flex gap-3 items-center">
@ -60,7 +60,7 @@ export default function Index() {
style={{ color: activeCollection?.color }} style={{ color: activeCollection?.color }}
className="sm:w-8 sm:h-8 w-6 h-6 mt-3 drop-shadow" className="sm:w-8 sm:h-8 w-6 h-6 mt-3 drop-shadow"
/> />
<p className="sm:text-4xl text-3xl capitalize text-sky-700 font-bold w-full py-1 break-words hyphens-auto"> <p className="sm:text-4xl text-3xl capitalize text-black dark:text-white w-full py-1 break-words hyphens-auto">
{activeCollection?.name} {activeCollection?.name}
</p> </p>
</div> </div>
@ -116,19 +116,19 @@ export default function Index() {
) : null} ) : null}
</div> </div>
<div className="text-gray-600 flex justify-between items-end gap-5"> <div className="text-gray-500 dark:text-gray-300 flex justify-between items-end gap-5">
<p>{activeCollection?.description}</p> <p>{activeCollection?.description}</p>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div className="relative"> <div className="relative">
<div <div
onClick={() => setSortDropdown(!sortDropdown)} onClick={() => setSortDropdown(!sortDropdown)}
id="sort-dropdown" id="sort-dropdown"
className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 duration-100 p-1" className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faSort} icon={faSort}
id="sort-dropdown" id="sort-dropdown"
className="w-5 h-5 text-gray-500" className="w-5 h-5 text-gray-500 dark:text-white"
/> />
</div> </div>
@ -144,13 +144,13 @@ export default function Index() {
<div <div
onClick={() => setExpandDropdown(!expandDropdown)} onClick={() => setExpandDropdown(!expandDropdown)}
id="expand-dropdown" id="expand-dropdown"
className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 duration-100 p-1" className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faEllipsis} icon={faEllipsis}
id="expand-dropdown" id="expand-dropdown"
title="More" title="More"
className="w-5 h-5 text-gray-500" className="w-5 h-5 text-gray-500 dark:text-white"
/> />
</div> </div>
{expandDropdown ? ( {expandDropdown ? (

View File

@ -37,9 +37,9 @@ export default function Collections() {
<div className="flex gap-2"> <div className="flex gap-2">
<FontAwesomeIcon <FontAwesomeIcon
icon={faFolder} icon={faFolder}
className="sm:w-8 sm:h-8 w-6 h-6 mt-2 text-sky-500 drop-shadow" className="sm:w-8 sm:h-8 w-6 h-6 mt-2 text-sky-500 dark:text-sky-300 drop-shadow"
/> />
<p className="sm:text-4xl text-3xl capitalize text-sky-700 font-bold"> <p className="sm:text-4xl text-3xl capitalize text-black dark:text-white">
All Collections All Collections
</p> </p>
</div> </div>
@ -47,12 +47,12 @@ export default function Collections() {
<div <div
onClick={() => setExpandDropdown(!expandDropdown)} onClick={() => setExpandDropdown(!expandDropdown)}
id="expand-dropdown" id="expand-dropdown"
className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 duration-100 p-1" className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faEllipsis} icon={faEllipsis}
id="expand-dropdown" id="expand-dropdown"
className="w-5 h-5 text-gray-500" className="w-5 h-5 text-gray-500 dark:text-white"
/> />
</div> </div>
@ -86,12 +86,12 @@ export default function Collections() {
<div <div
onClick={() => setSortDropdown(!sortDropdown)} onClick={() => setSortDropdown(!sortDropdown)}
id="sort-dropdown" id="sort-dropdown"
className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 duration-100 p-1" className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faSort} icon={faSort}
id="sort-dropdown" id="sort-dropdown"
className="w-5 h-5 text-gray-500" className="w-5 h-5 text-gray-500 dark:text-white"
/> />
</div> </div>
@ -111,7 +111,7 @@ export default function Collections() {
})} })}
<div <div
className="p-5 self-stretch bg-gradient-to-tr from-sky-100 from-10% via-gray-100 via-20% min-h-[12rem] rounded-2xl cursor-pointer shadow duration-100 hover:shadow-none flex flex-col gap-4 justify-center items-center group" className="p-5 self-stretch bg-gradient-to-tr from-sky-100 dark:from-gray-800 from-10% via-gray-100 via-20% to-white dark:to-neutral-800 to-100% min-h-[12rem] rounded-2xl cursor-pointer shadow duration-100 hover:shadow-none flex flex-col gap-4 justify-center items-center group"
onClick={() => { onClick={() => {
setModal({ setModal({
modal: "COLLECTION", modal: "COLLECTION",
@ -120,12 +120,12 @@ export default function Collections() {
}); });
}} }}
> >
<p className="text-sky-900 group-hover:opacity-0 duration-100"> <p className="text-black dark:text-white group-hover:opacity-0 duration-100">
New Collection New Collection
</p> </p>
<FontAwesomeIcon <FontAwesomeIcon
icon={faPlus} icon={faPlus}
className="w-8 h-8 text-sky-500 group-hover:w-12 group-hover:h-12 group-hover:-mt-10 duration-100" className="w-8 h-8 text-sky-500 dark:text-sky-300 group-hover:w-12 group-hover:h-12 group-hover:-mt-10 duration-100"
/> />
</div> </div>
</div> </div>

View File

@ -5,18 +5,18 @@ import React from "react";
export default function EmailConfirmaion() { export default function EmailConfirmaion() {
return ( return (
<CenteredForm> <CenteredForm>
<div className="p-2 sm:w-[30rem] w-80 rounded-2xl shadow-md m-auto border border-sky-100 bg-slate-50 text-sky-800"> <div className="p-4 sm:w-[30rem] w-80 rounded-2xl shadow-md m-auto border border-sky-100 dark:border-neutral-700 bg-slate-50 text-black dark:text-white dark:bg-neutral-800">
<p className="text-center text-xl font-bold mb-2 text-black"> <p className="text-center text-xl font-bold mb-2">
Please check your Email Please check your Email
</p> </p>
<p>A sign in link has been sent to your email address.</p> <p>A sign in link has been sent to your email address.</p>
<p>You can safely close this page.</p> <p>You can safely close this page.</p>
<hr className="my-5" /> <hr className="my-5 dark:border-neutral-700" />
<p className="text-sm text-gray-500 "> <p className="text-sm text-gray-500 dark:text-gray-400">
If you didn&apos;t receive anything, go to the{" "} If you didn&apos;t receive anything, go to the{" "}
<Link href="/forgot" className="font-bold"> <Link href="/forgot" className="font-bold underline">
Password Recovery Password Recovery
</Link>{" "} </Link>{" "}
page and enter your Email to resend the sign in link. page and enter your Email to resend the sign in link.

View File

@ -83,9 +83,9 @@ export default function Dashboard() {
<div className="flex gap-2"> <div className="flex gap-2">
<FontAwesomeIcon <FontAwesomeIcon
icon={faChartSimple} icon={faChartSimple}
className="sm:w-8 sm:h-8 w-6 h-6 mt-2 text-sky-500 drop-shadow" className="sm:w-8 sm:h-8 w-6 h-6 mt-2 text-sky-500 dark:text-sky-300 drop-shadow"
/> />
<p className="sm:text-4xl text-3xl capitalize text-sky-700 font-bold"> <p className="sm:text-4xl text-3xl capitalize text-black dark:text-white">
Dashboard Dashboard
</p> </p>
</div> </div>
@ -95,24 +95,28 @@ export default function Dashboard() {
<div className="flex flex-col md:flex-row md:items-center justify-evenly gap-2 mb-10"> <div className="flex flex-col md:flex-row md:items-center justify-evenly gap-2 mb-10">
<div className="flex items-baseline gap-2"> <div className="flex items-baseline gap-2">
<p className="font-bold text-6xl text-sky-700">{numberOfLinks}</p> <p className="font-bold text-6xl text-sky-500 dark:text-sky-300">
<p className="text-sky-900 text-xl"> {numberOfLinks}
</p>
<p className="text-black dark:text-white text-xl">
{numberOfLinks === 1 ? "Link" : "Links"} {numberOfLinks === 1 ? "Link" : "Links"}
</p> </p>
</div> </div>
<div className="flex items-baseline gap-2"> <div className="flex items-baseline gap-2">
<p className="font-bold text-6xl text-sky-700"> <p className="font-bold text-6xl text-sky-500 dark:text-sky-300">
{collections.length} {collections.length}
</p> </p>
<p className="text-sky-900 text-xl"> <p className="text-black dark:text-white text-xl">
{collections.length === 1 ? "Collection" : "Collections"} {collections.length === 1 ? "Collection" : "Collections"}
</p> </p>
</div> </div>
<div className="flex items-baseline gap-2"> <div className="flex items-baseline gap-2">
<p className="font-bold text-6xl text-sky-700">{tags.length}</p> <p className="font-bold text-6xl text-sky-500 dark:text-sky-300">
<p className="text-sky-900 text-xl"> {tags.length}
</p>
<p className="text-black dark:text-white text-xl">
{tags.length === 1 ? "Tag" : "Tags"} {tags.length === 1 ? "Tag" : "Tags"}
</p> </p>
</div> </div>
@ -129,15 +133,17 @@ export default function Dashboard() {
onClick={() => { onClick={() => {
setLinkPinDisclosure(!linkPinDisclosure); setLinkPinDisclosure(!linkPinDisclosure);
}} }}
className="flex justify-between gap-2 items-baseline shadow active:shadow-inner duration-100 py-2 px-4 rounded-full" className="flex justify-between gap-2 items-baseline shadow active:shadow-inner dark:bg-neutral-700 duration-100 py-2 px-4 rounded-full"
> >
<p className="text-sky-700 text-xl">Pinned Links</p> <p className="text-black dark:text-white text-xl">
Pinned Links
</p>
<div className="text-sky-700 flex items-center gap-2"> <div className="text-black dark:text-white flex items-center gap-2">
{linkPinDisclosure ? "Hide" : "Show"} {linkPinDisclosure ? "Hide" : "Show"}
<FontAwesomeIcon <FontAwesomeIcon
icon={faChevronDown} icon={faChevronDown}
className={`w-4 h-4 text-sky-300 ${ className={`w-4 h-4 text-black dark:text-white ${
linkPinDisclosure ? "rotate-reverse" : "rotate" linkPinDisclosure ? "rotate-reverse" : "rotate"
}`} }`}
/> />
@ -163,11 +169,11 @@ export default function Dashboard() {
</div> </div>
</Disclosure> </Disclosure>
) : ( ) : (
<div className="border border-solid border-sky-100 w-full mx-auto md:w-2/3 p-10 rounded-2xl"> <div className="border border-solid border-sky-100 dark:border-neutral-700 w-full mx-auto md:w-2/3 p-10 rounded-2xl">
<p className="text-center text-2xl text-sky-700"> <p className="text-center text-2xl text-black dark:text-white">
No Pinned Links No Pinned Links
</p> </p>
<p className="text-center text-sky-900 text-sm"> <p className="text-center text-black dark:text-white text-sm">
You can Pin Links by clicking on the three dots on each Link and You can Pin Links by clicking on the three dots on each Link and
clicking &quot;Pin to Dashboard.&quot; clicking &quot;Pin to Dashboard.&quot;
</p> </p>
@ -182,13 +188,13 @@ export default function Dashboard() {
}} }}
className="flex justify-between gap-2 items-baseline shadow active:shadow-inner duration-100 py-2 px-4 rounded-full" className="flex justify-between gap-2 items-baseline shadow active:shadow-inner duration-100 py-2 px-4 rounded-full"
> >
<p className="text-sky-700 text-xl">Pinned Collections</p> <p className="text-black text-xl">Pinned Collections</p>
<div className="text-sky-700 flex items-center gap-2"> <div className="text-black flex items-center gap-2">
{collectionPinDisclosure ? "Hide" : "Show"} {collectionPinDisclosure ? "Hide" : "Show"}
<FontAwesomeIcon <FontAwesomeIcon
icon={faChevronDown} icon={faChevronDown}
className={`w-4 h-4 text-sky-300 ${ className={`w-4 h-4 text-black ${
collectionPinDisclosure ? "rotate-reverse" : "rotate" collectionPinDisclosure ? "rotate-reverse" : "rotate"
}`} }`}
/> />
@ -219,13 +225,13 @@ export default function Dashboard() {
}} }}
className="flex justify-between gap-2 items-baseline shadow active:shadow-inner duration-100 py-2 px-4 rounded-full" className="flex justify-between gap-2 items-baseline shadow active:shadow-inner duration-100 py-2 px-4 rounded-full"
> >
<p className="text-sky-700 text-xl">Pinned Tags</p> <p className="text-black text-xl">Pinned Tags</p>
<div className="text-sky-700 flex items-center gap-2"> <div className="text-black flex items-center gap-2">
{tagPinDisclosure ? "Hide" : "Show"} {tagPinDisclosure ? "Hide" : "Show"}
<FontAwesomeIcon <FontAwesomeIcon
icon={faChevronDown} icon={faChevronDown}
className={`w-4 h-4 text-sky-300 ${ className={`w-4 h-4 text-black ${
tagPinDisclosure ? "rotate-reverse" : "rotate" tagPinDisclosure ? "rotate-reverse" : "rotate"
}`} }`}
/> />
@ -244,7 +250,7 @@ export default function Dashboard() {
<Link <Link
href={`/tags/${e.id}`} href={`/tags/${e.id}`}
key={i} key={i}
className="px-2 py-1 bg-sky-200 rounded-full hover:opacity-60 duration-100 text-sky-700" className="px-2 py-1 bg-sky-200 rounded-full hover:opacity-60 duration-100 text-black"
> >
{e.name} {e.name}
</Link> </Link>

View File

@ -40,27 +40,31 @@ export default function Forgot() {
return ( return (
<CenteredForm> <CenteredForm>
<div className="p-2 flex flex-col gap-3 justify-between sm:w-[30rem] w-80 bg-slate-50 rounded-2xl shadow-md border border-sky-100"> <div className="p-4 flex flex-col gap-3 justify-between sm:w-[30rem] w-80 bg-slate-50 dark:border-neutral-700 dark:bg-neutral-800 rounded-2xl shadow-md border border-sky-100">
<p className="text-2xl text-black font-bold">Password Recovery</p> <p className="text-2xl text-black dark:text-white font-bold">
Password Recovery
</p>
<div> <div>
<p className="text-md text-black"> <p className="text-md text-black dark:text-white">
Enter your Email so we can send you a link to recover your account. Enter your Email so we can send you a link to recover your account.
Make sure to change your password in the profile settings Make sure to change your password in the profile settings
afterwards. afterwards.
</p> </p>
<p className="text-sm text-gray-500"> <p className="text-sm text-gray-500 dark:text-gray-400">
You wont get logged in if you haven&apos;t created an account yet. You wont get logged in if you haven&apos;t created an account yet.
</p> </p>
</div> </div>
<div> <div>
<p className="text-sm text-sky-700 w-fit font-semibold mb-1">Email</p> <p className="text-sm text-black dark:text-white w-fit font-semibold mb-1">
Email
</p>
<input <input
type="text" type="text"
placeholder="johnny@example.com" placeholder="johnny@example.com"
value={form.email} value={form.email}
onChange={(e) => setForm({ ...form, email: e.target.value })} onChange={(e) => setForm({ ...form, email: e.target.value })}
className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none dark:focus:border-sky-600 dark:border-neutral-700 dark:bg-neutral-900 focus:border-sky-700 duration-100"
/> />
</div> </div>
@ -71,7 +75,10 @@ export default function Forgot() {
loading={submitLoader} loading={submitLoader}
/> />
<div className="flex items-baseline gap-1 justify-center"> <div className="flex items-baseline gap-1 justify-center">
<Link href={"/login"} className="block text-sky-700 font-bold"> <Link
href={"/login"}
className="block text-black dark:text-white font-bold"
>
Go back Go back
</Link> </Link>
</div> </div>

View File

@ -24,9 +24,9 @@ export default function Links() {
<div className="flex gap-2"> <div className="flex gap-2">
<FontAwesomeIcon <FontAwesomeIcon
icon={faLink} icon={faLink}
className="sm:w-8 sm:h-8 w-6 h-6 mt-2 text-sky-500 drop-shadow" className="sm:w-8 sm:h-8 w-6 h-6 mt-2 text-sky-500 dark:text-sky-300 drop-shadow"
/> />
<p className="sm:text-4xl text-3xl capitalize text-sky-700 font-bold"> <p className="sm:text-4xl text-3xl capitalize text-black dark:text-white">
All Links All Links
</p> </p>
</div> </div>
@ -35,12 +35,12 @@ export default function Links() {
<div <div
onClick={() => setSortDropdown(!sortDropdown)} onClick={() => setSortDropdown(!sortDropdown)}
id="sort-dropdown" id="sort-dropdown"
className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 duration-100 p-1" className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faSort} icon={faSort}
id="sort-dropdown" id="sort-dropdown"
className="w-5 h-5 text-gray-500" className="w-5 h-5 text-gray-500 dark:text-gray-200"
/> />
</div> </div>

View File

@ -47,13 +47,13 @@ export default function Login() {
return ( return (
<CenteredForm text="Sign in to your account"> <CenteredForm text="Sign in to your account">
<div className="p-2 flex flex-col gap-3 justify-between sm:w-[30rem] w-80 bg-slate-50 rounded-2xl shadow-md border border-sky-100"> <div className="p-4 flex flex-col gap-3 justify-between sm:w-[30rem] w-80 bg-slate-50 dark:bg-neutral-800 rounded-2xl shadow-md border border-sky-100 dark:border-neutral-700">
<p className="text-2xl text-black text-center font-bold"> <p className="text-2xl text-black dark:text-white text-center font-bold">
Enter your credentials Enter your credentials
</p> </p>
<div> <div>
<p className="text-sm text-sky-700 w-fit font-semibold mb-1"> <p className="text-sm text-black dark:text-white w-fit font-semibold mb-1">
Username Username
{emailEnabled ? "/Email" : undefined} {emailEnabled ? "/Email" : undefined}
</p> </p>
@ -63,12 +63,12 @@ export default function Login() {
placeholder="johnny" placeholder="johnny"
value={form.username} value={form.username}
onChange={(e) => setForm({ ...form, username: e.target.value })} onChange={(e) => setForm({ ...form, username: e.target.value })}
className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-2 mx-auto border-sky-100 dark:border-neutral-700 dark:bg-neutral-900 border-solid border outline-none focus:border-sky-300 dark:focus:border-sky-600 duration-100"
/> />
</div> </div>
<div> <div>
<p className="text-sm text-sky-700 w-fit font-semibold mb-1"> <p className="text-sm text-black dark:text-white w-fit font-semibold mb-1">
Password Password
</p> </p>
@ -77,11 +77,14 @@ export default function Login() {
placeholder="••••••••••••••" placeholder="••••••••••••••"
value={form.password} value={form.password}
onChange={(e) => setForm({ ...form, password: e.target.value })} onChange={(e) => setForm({ ...form, password: e.target.value })}
className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-2 mx-auto border-sky-100 dark:border-neutral-700 dark:bg-neutral-900 border-solid border outline-none focus:border-sky-300 dark:focus:border-sky-600 duration-100"
/> />
{emailEnabled && ( {emailEnabled && (
<div className="w-fit ml-auto mt-1"> <div className="w-fit ml-auto mt-1">
<Link href={"/forgot"} className="text-gray-500 font-semibold"> <Link
href={"/forgot"}
className="text-gray-500 dark:text-gray-400 font-semibold"
>
Forgot Password? Forgot Password?
</Link> </Link>
</div> </div>
@ -95,8 +98,11 @@ export default function Login() {
loading={submitLoader} loading={submitLoader}
/> />
<div className="flex items-baseline gap-1 justify-center"> <div className="flex items-baseline gap-1 justify-center">
<p className="w-fit text-gray-500">New here?</p> <p className="w-fit text-gray-500 dark:text-gray-400">New here?</p>
<Link href={"/register"} className="block text-sky-700 font-bold"> <Link
href={"/register"}
className="block text-black dark:text-white font-semibold"
>
Sign Up Sign Up
</Link> </Link>
</div> </div>

View File

@ -45,9 +45,7 @@ export default function PublicCollections() {
<div <div
className={`text-center bg-gradient-to-tr from-sky-100 from-10% via-gray-100 via-20% rounded-3xl shadow-lg p-5`} className={`text-center bg-gradient-to-tr from-sky-100 from-10% via-gray-100 via-20% rounded-3xl shadow-lg p-5`}
> >
<p className="text-5xl text-sky-700 font-bold mb-5 capitalize"> <p className="text-5xl text-black mb-5 capitalize">{data.name}</p>
{data.name}
</p>
{data.description && ( {data.description && (
<> <>
@ -64,7 +62,7 @@ export default function PublicCollections() {
</div> </div>
{/* <p className="text-center font-bold text-gray-500"> {/* <p className="text-center font-bold text-gray-500">
List created with <span className="text-sky-700">Linkwarden.</span> List created with <span className="text-black">Linkwarden.</span>
</p> */} </p> */}
</div> </div>
) : ( ) : (

View File

@ -98,12 +98,12 @@ export default function Register() {
: "Create a new account" : "Create a new account"
} }
> >
<div className="p-2 flex flex-col gap-3 justify-between sm:w-[30rem] w-80 bg-slate-50 rounded-2xl shadow-md border border-sky-100"> <div className="p-4 flex flex-col gap-3 justify-between sm:w-[30rem] w-80 bg-slate-50 dark:bg-neutral-800 rounded-2xl shadow-md border border-sky-100 dark:border-neutral-700">
<p className="text-2xl text-black text-center font-bold"> <p className="text-2xl text-black dark:text-white text-center font-bold">
Enter your details Enter your details
</p> </p>
<div> <div>
<p className="text-sm text-sky-700 w-fit font-semibold mb-1"> <p className="text-sm text-black dark:text-white w-fit font-semibold mb-1">
Display Name Display Name
</p> </p>
@ -112,13 +112,13 @@ export default function Register() {
placeholder="Johnny" placeholder="Johnny"
value={form.name} value={form.name}
onChange={(e) => setForm({ ...form, name: e.target.value })} onChange={(e) => setForm({ ...form, name: e.target.value })}
className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-2 mx-auto border-sky-100 dark:border-neutral-700 dark:bg-neutral-900 border-solid border outline-none focus:border-sky-700 dark:focus:border-sky-600 duration-100"
/> />
</div> </div>
{emailEnabled ? undefined : ( {emailEnabled ? undefined : (
<div> <div>
<p className="text-sm text-sky-700 w-fit font-semibold mb-1"> <p className="text-sm text-black dark:text-white w-fit font-semibold mb-1">
Username Username
</p> </p>
@ -127,14 +127,14 @@ export default function Register() {
placeholder="john" placeholder="john"
value={form.username} value={form.username}
onChange={(e) => setForm({ ...form, username: e.target.value })} onChange={(e) => setForm({ ...form, username: e.target.value })}
className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-2 mx-auto border-sky-100 dark:border-neutral-700 dark:bg-neutral-900 border-solid border outline-none focus:border-sky-700 dark:focus:border-sky-600 duration-100"
/> />
</div> </div>
)} )}
{emailEnabled ? ( {emailEnabled ? (
<div> <div>
<p className="text-sm text-sky-700 w-fit font-semibold mb-1"> <p className="text-sm text-black dark:text-white w-fit font-semibold mb-1">
Email Email
</p> </p>
@ -143,13 +143,13 @@ export default function Register() {
placeholder="johnny@example.com" placeholder="johnny@example.com"
value={form.email} value={form.email}
onChange={(e) => setForm({ ...form, email: e.target.value })} onChange={(e) => setForm({ ...form, email: e.target.value })}
className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-2 mx-auto border-sky-100 dark:border-neutral-700 dark:bg-neutral-900 border-solid border outline-none focus:border-sky-700 dark:focus:border-sky-600 duration-100"
/> />
</div> </div>
) : undefined} ) : undefined}
<div className="w-full"> <div className="w-full">
<p className="text-sm text-sky-700 w-fit font-semibold mb-1"> <p className="text-sm text-black dark:text-white w-fit font-semibold mb-1">
Password Password
</p> </p>
@ -158,12 +158,12 @@ export default function Register() {
placeholder="••••••••••••••" placeholder="••••••••••••••"
value={form.password} value={form.password}
onChange={(e) => setForm({ ...form, password: e.target.value })} onChange={(e) => setForm({ ...form, password: e.target.value })}
className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-2 mx-auto border-sky-100 dark:border-neutral-700 dark:bg-neutral-900 border-solid border outline-none focus:border-sky-700 dark:focus:border-sky-600 duration-100"
/> />
</div> </div>
<div className="w-full"> <div className="w-full">
<p className="text-sm text-sky-700 w-fit font-semibold mb-1"> <p className="text-sm text-black dark:text-white w-fit font-semibold mb-1">
Confirm Password Confirm Password
</p> </p>
@ -174,31 +174,34 @@ export default function Register() {
onChange={(e) => onChange={(e) =>
setForm({ ...form, passwordConfirmation: e.target.value }) setForm({ ...form, passwordConfirmation: e.target.value })
} }
className="w-full rounded-md p-2 mx-auto border-sky-100 border-solid border outline-none focus:border-sky-700 duration-100" className="w-full rounded-md p-2 mx-auto border-sky-100 dark:border-neutral-700 dark:bg-neutral-900 border-solid border outline-none focus:border-sky-700 dark:focus:border-sky-600 duration-100"
/> />
</div> </div>
{process.env.NEXT_PUBLIC_STRIPE_IS_ACTIVE ? ( {process.env.NEXT_PUBLIC_STRIPE_IS_ACTIVE ? (
<div> <div>
<p className="text-xs text-gray-500"> <p className="text-xs text-gray-500 dark:text-gray-400">
By signing up, you agree to our{" "} By signing up, you agree to our{" "}
<Link href="https://linkwarden.app/tos" className="font-semibold"> <Link
href="https://linkwarden.app/tos"
className="font-semibold underline"
>
Terms of Service Terms of Service
</Link>{" "} </Link>{" "}
and{" "} and{" "}
<Link <Link
href="https://linkwarden.app/privacy-policy" href="https://linkwarden.app/privacy-policy"
className="font-semibold" className="font-semibold underline"
> >
Privacy Policy Privacy Policy
</Link> </Link>
. .
</p> </p>
<p className="text-xs text-gray-500"> <p className="text-xs text-gray-500 dark:text-gray-400">
Need help?{" "} Need help?{" "}
<Link <Link
href="mailto:support@linkwarden.app" href="mailto:support@linkwarden.app"
className="font-semibold" className="font-semibold underline"
> >
Get in touch Get in touch
</Link> </Link>
@ -214,8 +217,13 @@ export default function Register() {
loading={submitLoader} loading={submitLoader}
/> />
<div className="flex items-baseline gap-1 justify-center"> <div className="flex items-baseline gap-1 justify-center">
<p className="w-fit text-gray-500">Already have an account?</p> <p className="w-fit text-gray-500 dark:text-gray-400">
<Link href={"/login"} className="block text-sky-700 font-bold"> Already have an account?
</p>
<Link
href={"/login"}
className="block text-black dark:text-white font-bold"
>
Login Login
</Link> </Link>
</div> </div>

View File

@ -40,9 +40,9 @@ export default function Links() {
<div className="flex gap-2"> <div className="flex gap-2">
<FontAwesomeIcon <FontAwesomeIcon
icon={faSearch} icon={faSearch}
className="sm:w-8 sm:h-8 w-6 h-6 mt-2 text-sky-500 drop-shadow" className="sm:w-8 sm:h-8 w-6 h-6 mt-2 text-sky-500 dark:text-sky-300 drop-shadow"
/> />
<p className="sm:text-4xl text-3xl capitalize text-sky-700 font-bold"> <p className="sm:text-4xl text-3xl capitalize text-black dark:text-white">
Search Results Search Results
</p> </p>
</div> </div>
@ -53,12 +53,12 @@ export default function Links() {
<div <div
onClick={() => setFilterDropdown(!filterDropdown)} onClick={() => setFilterDropdown(!filterDropdown)}
id="filter-dropdown" id="filter-dropdown"
className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 duration-100 p-1" className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faFilter} icon={faFilter}
id="filter-dropdown" id="filter-dropdown"
className="w-5 h-5 text-gray-500" className="w-5 h-5 text-gray-500 dark:text-white"
/> />
</div> </div>
@ -75,12 +75,12 @@ export default function Links() {
<div <div
onClick={() => setSortDropdown(!sortDropdown)} onClick={() => setSortDropdown(!sortDropdown)}
id="sort-dropdown" id="sort-dropdown"
className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 duration-100 p-1" className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faSort} icon={faSort}
id="sort-dropdown" id="sort-dropdown"
className="w-5 h-5 text-gray-500" className="w-5 h-5 text-gray-500 dark:text-white"
/> />
</div> </div>
@ -99,9 +99,9 @@ export default function Links() {
return <LinkCard key={i} link={e} count={i} />; return <LinkCard key={i} link={e} count={i} />;
}) })
) : ( ) : (
<p className="text-sky-900"> <p className="text-black dark:text-white">
Nothing found.{" "} Nothing found.{" "}
<span className="text-sky-700 font-bold text-xl" title="Shruggie"> <span className="font-bold text-xl" title="Shruggie">
¯\_()_/¯ ¯\_()_/¯
</span> </span>
</p> </p>

View File

@ -28,10 +28,11 @@ export default function Subscribe() {
<CenteredForm <CenteredForm
text={`${ text={`${
process.env.NEXT_PUBLIC_TRIAL_PERIOD_DAYS || 14 process.env.NEXT_PUBLIC_TRIAL_PERIOD_DAYS || 14
}-Day free trial, then $ }-Day free trial, then $${
${process.env.NEXT_PUBLIC_PRICING}/month afterwards`} process.env.NEXT_PUBLIC_PRICING
}/month afterwards`}
> >
<div className="p-2 mx-auto flex flex-col gap-3 justify-between sm:w-[30rem] w-80 bg-slate-50 rounded-2xl shadow-md border border-sky-100"> <div className="p-2 mx-auto flex flex-col gap-3 justify-between sm:w-[30rem] dark:border-neutral-700 w-80 bg-slate-50 dark:bg-neutral-800 rounded-2xl shadow-md border border-sky-100">
<p className="text-2xl text-center font-bold"> <p className="text-2xl text-center font-bold">
Subscribe to Linkwarden! Subscribe to Linkwarden!
</p> </p>
@ -56,7 +57,7 @@ export default function Subscribe() {
<div <div
onClick={() => signOut()} onClick={() => signOut()}
className="w-fit mx-auto cursor-pointer text-gray-500 font-semibold " className="w-fit mx-auto cursor-pointer text-gray-500 dark:text-gray-400 font-semibold "
> >
Sign Out Sign Out
</div> </div>

View File

@ -36,9 +36,9 @@ export default function Index() {
<div className="flex gap-2"> <div className="flex gap-2">
<FontAwesomeIcon <FontAwesomeIcon
icon={faHashtag} icon={faHashtag}
className="sm:w-8 sm:h-8 w-6 h-6 mt-2 text-sky-500" className="sm:w-8 sm:h-8 w-6 h-6 mt-2 text-sky-500 dark:text-sky-300"
/> />
<p className="sm:text-4xl text-3xl capitalize text-sky-700 font-bold"> <p className="sm:text-4xl text-3xl capitalize text-black dark:text-white">
{activeTag?.name} {activeTag?.name}
</p> </p>
</div> </div>
@ -48,12 +48,12 @@ export default function Index() {
<div <div
onClick={() => setSortDropdown(!sortDropdown)} onClick={() => setSortDropdown(!sortDropdown)}
id="sort-dropdown" id="sort-dropdown"
className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 duration-100 p-1" className="inline-flex rounded-md cursor-pointer hover:bg-slate-200 hover:dark:bg-neutral-700 duration-100 p-1"
> >
<FontAwesomeIcon <FontAwesomeIcon
icon={faSort} icon={faSort}
id="sort-dropdown" id="sort-dropdown"
className="w-5 h-5 text-gray-500" className="w-5 h-5 text-gray-500 dark:text-white"
/> />
</div> </div>

View File

@ -136,11 +136,6 @@
bottom: 0; bottom: 0;
left: 0; left: 0;
pointer-events: none; pointer-events: none;
background-image: linear-gradient(
to bottom,
rgba(255, 255, 255, 0),
rgba(255, 255, 255, 1) 90%
);
width: 100%; width: 100%;
height: 4rem; height: 4rem;
} }
@ -151,11 +146,71 @@
top: 0; top: 0;
left: 0; left: 0;
pointer-events: none; pointer-events: none;
width: 100%;
height: 4rem;
}
/* For light mode */
.link-banner::after {
background-image: linear-gradient(
to bottom,
rgba(255, 255, 255, 0),
rgba(255, 255, 255, 1) 90%
);
}
.link-banner::before {
background-image: linear-gradient( background-image: linear-gradient(
to top, to top,
rgba(255, 255, 255, 0), rgba(255, 255, 255, 0),
rgba(255, 255, 255, 1) 90% rgba(255, 255, 255, 1) 90%
); );
width: 100%; }
height: 4rem;
/* For dark mode */
.banner-dark-mode .link-banner::after {
background-image: linear-gradient(
to bottom,
rgba(255, 255, 255, 0),
#171717 90%
);
}
.banner-dark-mode .link-banner::before {
background-image: linear-gradient(
to top,
rgba(255, 255, 255, 0),
#171717 90%
);
}
/* Theme */
@layer base {
body {
@apply dark:bg-neutral-900 bg-white dark:text-white;
}
}
/* react-select */
@layer components {
.react-select-container .react-select__control {
@apply dark:bg-neutral-900 dark:border-neutral-700 dark:hover:border-neutral-500;
}
.react-select-container {
@apply dark:border-neutral-700;
}
.react-select-container .react-select__menu {
@apply dark:bg-neutral-900 dark:border-neutral-700 border;
}
.react-select-container .react-select__option {
@apply dark:hover:bg-neutral-800;
}
.react-select-container .react-select__input-container,
.react-select-container .react-select__single-value {
@apply dark:text-white;
}
} }

View File

@ -1,6 +1,7 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
module.exports = { module.exports = {
darkMode: "class",
content: [ content: [
"./app/**/*.{js,ts,jsx,tsx}", "./app/**/*.{js,ts,jsx,tsx}",
"./pages/**/*.{js,ts,jsx,tsx}", "./pages/**/*.{js,ts,jsx,tsx}",
@ -9,8 +10,5 @@ module.exports = {
// For the "layouts" directory // For the "layouts" directory
"./layouts/**/*.{js,ts,jsx,tsx}", "./layouts/**/*.{js,ts,jsx,tsx}",
], ],
theme: {
extend: {},
},
plugins: [], plugins: [],
}; };

View File

@ -3558,6 +3558,11 @@ next-auth@^4.22.1:
preact-render-to-string "^5.1.19" preact-render-to-string "^5.1.19"
uuid "^8.3.2" uuid "^8.3.2"
next-themes@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.2.1.tgz#0c9f128e847979daf6c67f70b38e6b6567856e45"
integrity sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==
next@13.4.12: next@13.4.12:
version "13.4.12" version "13.4.12"
resolved "https://registry.yarnpkg.com/next/-/next-13.4.12.tgz#809b21ea0aabbe88ced53252c88c4a5bd5af95df" resolved "https://registry.yarnpkg.com/next/-/next-13.4.12.tgz#809b21ea0aabbe88ced53252c88c4a5bd5af95df"