Compare commits

...

12 Commits

Author SHA1 Message Date
Daniel ae6656e0ec Merge pull request #386 from treyg/global-theming-2.4
Global theming support
2024-01-02 07:30:01 -05:00
daniel31x13 fbca98984b Revert "updated README.md"
This reverts commit 4da2310e95.
2024-01-02 07:16:11 -05:00
daniel31x13 4da2310e95 updated README.md 2024-01-02 07:12:18 -05:00
daniel31x13 93bcfc67fe updated SECURITY.md 2024-01-02 07:01:04 -05:00
Daniel d16b296b15 Merge pull request #390 from QAComet/qacomet/worker-environment-variables
fix: load environment variables in the worker script
2024-01-01 17:12:46 -05:00
QAComet 3fc61ac5ce fix: load environment variables in the worker script 2024-01-01 15:09:55 -07:00
daniel31x13 ced51e4801 minor fix 2024-01-01 10:37:20 -05:00
Daniel 254c090605 Merge pull request #387 from linkwarden/dev
Dev
2023-12-31 16:05:41 -05:00
daniel31x13 2a83ced9d8 updated README 2023-12-31 16:05:18 -05:00
daniel31x13 52d333f085 updated README 2023-12-31 16:03:19 -05:00
Trey Gordon 7e9eae0ef2 style: change to neutral to handle new themes 2023-12-29 12:29:10 -05:00
Trey Gordon 6b28abc405 feat: add new theming options 2023-12-29 12:28:43 -05:00
33 changed files with 646 additions and 484 deletions
+12 -10
View File
@@ -1,17 +1,19 @@
# Security Policy # Security
## Supported Versions The Linkwarden team and community take security bugs in Linkwarden seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
| Version | Supported | # Reporting Security Issues
| ------- | --------- |
| 1.x.x | ✅ |
## Reporting a Vulnerability **Please do not report security vulnerabilities through public GitHub issues.**
First off, we really appreciate the time you spent! Instead, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/linkwarden/linkwarden/security/advisories/new) tab.
If you found a vulnerability, these are the ways you can reach us: You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message:
[security@linkwarden.app](mailto:security@linkwarden.app)
Email: [security@linkwarden.app](mailto:security@linkwarden.app)
Or you can directly DM me via Twitter: [@daniel31x13](https://twitter.com/Daniel31X13). After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance.
# Preferred Languages
We prefer all communications to be in English.
+10 -6
View File
@@ -27,17 +27,21 @@ Additionally, Linkwarden is designed with collaboration in mind, sharing links w
<img src="./assets/dashboard.png" /> <img src="./assets/dashboard.png" />
<div align="center"> <div align="center">
<img src="./assets/all_links.png" width="32%" /> <img src="./assets/all_links.jpg" width="23%" />
<img src="./assets/all_collections.png" width="32%" /> <img src="./assets/list_view.jpg" width="23%" />
<img src="./assets/manage_team.png" width="32%" /> <img src="./assets/all_collections.jpg" width="23%" />
<img src="./assets/readable_view.png" width="32%" /> <img src="./assets/manage_team.jpg" width="23%" />
<img src="./assets/public_page.png" width="32%" /> <img src="./assets/readable_view.jpg" width="23%" />
<img src="./assets/light_mode.png" width="32%" /> <img src="./assets/preserved_formats.jpg" width="23%" />
<img src="./assets/public_page.jpg" width="23%" />
<img src="./assets/light_dashboard.jpg" width="23%" />
</div> </div>
<details> <details>
Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 654 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 799 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 369 KiB

After

Width:  |  Height:  |  Size: 786 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 785 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 634 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 664 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 657 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 945 KiB

+6 -6
View File
@@ -26,13 +26,13 @@ export default function Navbar() {
const { width } = useWindowDimensions(); const { width } = useWindowDimensions();
const handleToggle = () => { const handleToggle = () => {
if (settings.theme === "dark") { const [colorTheme, mode] = (settings.theme || "default-light").split('-');
updateSettings({ theme: "light" }); const newMode = mode === "dark" ? "light" : "dark";
} else { const newTheme = `${colorTheme}-${newMode}`;
updateSettings({ theme: "dark" }); updateSettings({ theme: newTheme });
}
}; };
useEffect(() => { useEffect(() => {
setSidebar(false); setSidebar(false);
}, [width]); }, [width]);
@@ -143,7 +143,7 @@ export default function Navbar() {
tabIndex={0} tabIndex={0}
role="button" role="button"
> >
Switch to {settings.theme === "light" ? "Dark" : "Light"} Switch to {(settings.theme || "default-light").endsWith("-dark") ? "Light" : "Dark"}
</div> </div>
</li> </li>
<li> <li>
+29 -22
View File
@@ -6,32 +6,39 @@ type Props = {
}; };
export default function ToggleDarkMode({ className }: Props) { export default function ToggleDarkMode({ className }: Props) {
const { settings, updateSettings } = useLocalSettingsStore(); const { updateSettings } = useLocalSettingsStore();
const [theme, setTheme] = useState('default-light');
const [theme, setTheme] = useState(localStorage.getItem("theme"));
const handleToggle = (e: any) => {
setTheme(e.target.checked ? "dark" : "light");
};
useEffect(() => { useEffect(() => {
updateSettings({ theme: theme as string }); const storedTheme = localStorage.getItem("theme");
}, [theme]); if (storedTheme) {
setTheme(storedTheme);
} else {
// Default theme if not set in localStorage
localStorage.setItem("theme", "default-light");
setTheme("default-light");
}
console.log("Initial theme from localStorage:", storedTheme || "default-light");
}, []);
const handleToggle = () => {
const [currentColorTheme, currentMode] = theme.split('-');
const newMode = currentMode === 'light' ? 'dark' : 'light';
const newTheme = `${currentColorTheme}-${newMode}`;
setTheme(newTheme);
localStorage.setItem("theme", newTheme);
document.documentElement.setAttribute('data-theme', newTheme);
updateSettings({ theme: newTheme });
console.log("New theme set:", newTheme);
};
const isDarkMode = theme.endsWith('-dark');
return ( return (
<div <div className="tooltip tooltip-bottom" data-tip={`Switch to ${isDarkMode ? "Light" : "Dark"}`}>
className="tooltip tooltip-bottom" <label className={`swap swap-rotate btn-square text-neutral btn btn-ghost btn-sm ${className}`}>
data-tip={`Switch to ${settings.theme === "light" ? "Dark" : "Light"}`} <input type="checkbox" onChange={handleToggle} className="theme-controller" checked={isDarkMode} />
>
<label
className={`swap swap-rotate btn-square text-neutral btn btn-ghost btn-sm ${className}`}
>
<input
type="checkbox"
onChange={handleToggle}
className="theme-controller"
checked={localStorage.getItem("theme") === "light" ? false : true}
/>
<i className="bi-sun-fill text-xl swap-on"></i> <i className="bi-sun-fill text-xl swap-on"></i>
<i className="bi-moon-fill text-xl swap-off"></i> <i className="bi-moon-fill text-xl swap-off"></i>
</label> </label>
+2 -1
View File
@@ -11,7 +11,8 @@ services:
environment: environment:
- DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres - DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres
restart: always restart: always
image: ghcr.io/linkwarden/linkwarden:latest # build: . # uncomment this line to build from source
image: ghcr.io/linkwarden/linkwarden:latest # comment this line to build from source
ports: ports:
- 3000:3000 - 3000:3000
volumes: volumes:
+3 -3
View File
@@ -50,11 +50,11 @@ export default async function archiveHandler(link: LinksAndCollectionAndOwner) {
let imageExtension = "png"; let imageExtension = "png";
if (!link.url) linkType = link.type; if (!link.url) linkType = link.type;
else if (contentType === "application/pdf") linkType = "pdf"; else if (contentType?.includes("application/pdf")) linkType = "pdf";
else if (contentType?.startsWith("image")) { else if (contentType?.startsWith("image")) {
linkType = "image"; linkType = "image";
if (contentType === "image/jpeg") imageExtension = "jpeg"; if (contentType.includes("image/jpeg")) imageExtension = "jpeg";
else if (contentType === "image/png") imageExtension = "png"; else if (contentType.includes("image/png")) imageExtension = "png";
} }
const user = link.collection?.owner; const user = link.collection?.owner;
+1
View File
@@ -39,6 +39,7 @@
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"csstype": "^3.1.2", "csstype": "^3.1.2",
"dompurify": "^3.0.6", "dompurify": "^3.0.6",
"dotenv": "^16.3.1",
"eslint": "8.46.0", "eslint": "8.46.0",
"eslint-config-next": "13.4.9", "eslint-config-next": "13.4.9",
"formidable": "^3.5.1", "formidable": "^3.5.1",
+13 -1
View File
@@ -1,4 +1,4 @@
import React from "react"; import React, { useEffect } from "react";
import "@/styles/globals.css"; import "@/styles/globals.css";
import "bootstrap-icons/font/bootstrap-icons.css"; import "bootstrap-icons/font/bootstrap-icons.css";
import { SessionProvider } from "next-auth/react"; import { SessionProvider } from "next-auth/react";
@@ -14,6 +14,18 @@ export default function App({
}: AppProps<{ }: AppProps<{
session: Session; session: Session;
}>) { }>) {
useEffect(() => {
let theme = localStorage.getItem("theme");
if (!theme || !theme.includes("-")) {
theme = "default-dark"; // Default theme
localStorage.setItem("theme", theme);
}
document.documentElement.setAttribute('data-theme', theme);
}, []);
return ( return (
<SessionProvider <SessionProvider
session={pageProps.session} session={pageProps.session}
+4 -2
View File
@@ -104,8 +104,10 @@ export default function Index() {
className="h-[60rem] p-5 flex gap-3 flex-col" className="h-[60rem] p-5 flex gap-3 flex-col"
style={{ style={{
backgroundImage: `linear-gradient(${activeCollection?.color}20 10%, ${ backgroundImage: `linear-gradient(${activeCollection?.color}20 10%, ${
settings.theme === "dark" ? "#262626" : "#f3f4f6" (settings.theme || "default-light").endsWith("-dark") ? "#262626" : "#f3f4f6"
} 13rem, ${settings.theme === "dark" ? "#171717" : "#ffffff"} 100%)`, } 13rem, ${
(settings.theme || "default-light").endsWith("-dark") ? "#171717" : "#ffffff"
} 100%)`,
}} }}
> >
{activeCollection && ( {activeCollection && (
+2 -2
View File
@@ -155,7 +155,7 @@ export default function Dashboard() {
</div> </div>
<Link <Link
href="/links" href="/links"
className="flex items-center text-sm text-black/75 dark:text-white/75 gap-2 cursor-pointer" className="flex items-center text-sm text-neutral gap-2 cursor-pointer"
> >
View All View All
<i className="bi-chevron-right text-sm"></i> <i className="bi-chevron-right text-sm"></i>
@@ -264,7 +264,7 @@ export default function Dashboard() {
</div> </div>
<Link <Link
href="/links/pinned" href="/links/pinned"
className="flex items-center text-sm text-black/75 dark:text-white/75 gap-2 cursor-pointer" className="flex items-center text-sm text-neutral gap-2 cursor-pointer"
> >
View All View All
<i className="bi-chevron-right text-sm "></i> <i className="bi-chevron-right text-sm "></i>
+58 -39
View File
@@ -1,16 +1,16 @@
import SettingsLayout from "@/layouts/SettingsLayout"; import SettingsLayout from "@/layouts/SettingsLayout";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import useAccountStore from "@/store/account"; import useAccountStore from "@/store/account";
import { AccountSettings } from "@/types/global"; import { AccountSettings } from "@/types/global";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import React from "react";
import useLocalSettingsStore from "@/store/localSettings"; import useLocalSettingsStore from "@/store/localSettings";
export default function Appearance() { export default function Appearance() {
const { updateSettings } = useLocalSettingsStore(); const { updateSettings } = useLocalSettingsStore();
const { account, updateAccount } = useAccountStore();
const submit = async () => { const submit = async () => {
setSubmitLoader(true); setSubmitLoader(true);
const load = toast.loading("Applying..."); const load = toast.loading("Applying...");
const response = await updateAccount({ const response = await updateAccount({
@@ -18,17 +18,12 @@ export default function Appearance() {
}); });
toast.dismiss(load); toast.dismiss(load);
if (response.ok) { if (response.ok) {
toast.success("Settings Applied!"); toast.success("Settings Applied!");
} else toast.error(response.data as string); } else toast.error(response.data as string);
setSubmitLoader(false); setSubmitLoader(false);
}; };
const [submitLoader, setSubmitLoader] = useState(false); const [submitLoader, setSubmitLoader] = useState(false);
const { account, updateAccount } = useAccountStore();
const [user, setUser] = useState<AccountSettings>( const [user, setUser] = useState<AccountSettings>(
!objectIsEmpty(account) !objectIsEmpty(account)
? account ? account
@@ -48,6 +43,9 @@ export default function Appearance() {
} as unknown as AccountSettings) } as unknown as AccountSettings)
); );
// Combine colorTheme and mode into a single state
const [theme, setTheme] = useState(localStorage.getItem("theme") || "default-dark");
function objectIsEmpty(obj: object) { function objectIsEmpty(obj: object) {
return Object.keys(obj).length === 0; return Object.keys(obj).length === 0;
} }
@@ -56,51 +54,72 @@ export default function Appearance() {
if (!objectIsEmpty(account)) setUser({ ...account }); if (!objectIsEmpty(account)) setUser({ ...account });
}, [account]); }, [account]);
const handleThemeChange = (newThemePart: string, isColorTheme: boolean) => {
const currentTheme = localStorage.getItem("theme") || "default-light";
const [currentColorTheme, currentMode] = currentTheme.split('-');
const newTheme = isColorTheme ? `${newThemePart}-${currentMode}` : `${currentColorTheme}-${newThemePart}`;
localStorage.setItem("theme", newTheme);
document.documentElement.setAttribute('data-theme', newTheme);
updateSettings({ theme: newTheme });
// Update the theme state
setTheme(newTheme);
};
return ( return (
<SettingsLayout> <SettingsLayout>
<p className="capitalize text-3xl font-thin inline">Appearance</p> <p className="capitalize text-3xl font-thin inline">Appearance</p>
<div className="divider my-3"></div> <div className="divider my-3"></div>
<div className="flex flex-col gap-5"> <div className="flex flex-col gap-5">
<div> <div>
<p className="mb-3">Select Theme</p> <p className="mb-3">Select Mode</p>
<div className="flex gap-3 w-full"> <div className="grid grid-cols-2 gap-3">
<div {["light", "dark"].map((modeOption) => (
className={`w-full text-center outline-solid outline-neutral-content outline dark:outline-neutral-700 h-36 duration-100 rounded-md flex items-center justify-center cursor-pointer select-none bg-black ${ <button
localStorage.getItem("theme") === "dark" key={modeOption}
? "dark:outline-primary text-primary" onClick={() => handleThemeChange(modeOption, false)}
: "text-white" className={`w-full text-center h-36 duration-100 rounded-md flex items-center justify-center cursor-pointer select-none ${theme.endsWith(modeOption) ? "ring-2 ring-primary" : "ring-2 ring-neutral"}`}
}`}
onClick={() => updateSettings({ theme: "dark" })}
> >
<i className="bi-moon-fill text-6xl"></i> {modeOption === 'light' ?
<p className="ml-2 text-2xl">Dark</p> <i className={`bi-sun-fill text-6xl ${theme.endsWith(modeOption) ? "text-primary" : ""}`}></i> :
<i className={`bi-moon-fill text-6xl ${theme.endsWith(modeOption) ? "text-primary" : ""}`}></i>}
{/* <hr className="my-3 outline-1 outline-neutral-content dark:outline-neutral-700" /> */} <p className="ml-2 text-2xl">{modeOption.charAt(0).toUpperCase() + modeOption.slice(1)}</p>
</div> </button>
<div ))}
className={`w-full text-center outline-solid outline-neutral-content outline dark:outline-neutral-700 h-36 duration-100 rounded-md flex items-center justify-center cursor-pointer select-none bg-white ${
localStorage.getItem("theme") === "light"
? "outline-primary text-primary"
: "text-black"
}`}
onClick={() => updateSettings({ theme: "light" })}
>
<i className="bi-sun-fill text-6xl"></i>
<p className="ml-2 text-2xl">Light</p>
{/* <hr className="my-3 outline-1 outline-neutral-content dark:outline-neutral-700" /> */}
</div>
</div> </div>
</div> </div>
{/* <SubmitButton <div>
<p className="mb-3">Select Color Theme</p>
<div className="grid grid-cols-4 gap-3">
{["default", "red", "green", "orange"].map((colorTheme) => (
<button
key={colorTheme}
onClick={() => handleThemeChange(colorTheme, true)}
className={`w-full text-center h-36 duration-100 rounded-md flex items-center justify-center cursor-pointer select-none ${theme.startsWith(colorTheme) ? "ring-2 ring-primary" : "ring-2 ring-neutral"}`}
>
{colorTheme.charAt(0).toUpperCase() + colorTheme.slice(1)}
</button>
))}
</div>
</div>
<button
onClick={submit} onClick={submit}
loading={submitLoader} disabled={submitLoader}
label="Save" className="mt-2 mx-auto lg:mx-0 bg-primary text-white rounded-md px-4 py-2"
className="mt-2 mx-auto lg:mx-0" >
/> */} {submitLoader ? "Saving..." : "Save"}
</button>
</div> </div>
</SettingsLayout> </SettingsLayout>
); );
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

+1
View File
@@ -1,3 +1,4 @@
import 'dotenv/config';
import { Collection, Link, User } from "@prisma/client"; import { Collection, Link, User } from "@prisma/client";
import { prisma } from "../lib/api/db"; import { prisma } from "../lib/api/db";
import archiveHandler from "../lib/api/archiveHandler"; import archiveHandler from "../lib/api/archiveHandler";
+21 -16
View File
@@ -18,34 +18,39 @@ const useLocalSettingsStore = create<LocalSettingsStore>((set) => ({
viewMode: "", viewMode: "",
}, },
updateSettings: async (newSettings) => { updateSettings: async (newSettings) => {
if ( if (newSettings.theme) {
newSettings.theme &&
newSettings.theme !== localStorage.getItem("theme")
) {
localStorage.setItem("theme", newSettings.theme); localStorage.setItem("theme", newSettings.theme);
document.documentElement.setAttribute('data-theme', newSettings.theme);
const localTheme = localStorage.getItem("theme") || ""; if (newSettings.theme.endsWith("-dark")) {
document.documentElement.classList.add("dark");
document.querySelector("html")?.setAttribute("data-theme", localTheme); } else {
document.documentElement.classList.remove("dark");
}
} }
if ( if (newSettings.viewMode) {
newSettings.viewMode &&
newSettings.viewMode !== localStorage.getItem("viewMode")
) {
localStorage.setItem("viewMode", newSettings.viewMode); localStorage.setItem("viewMode", newSettings.viewMode);
// const localTheme = localStorage.getItem("viewMode") || "";
} }
set((state) => ({ settings: { ...state.settings, ...newSettings } })); set((state) => ({ settings: { ...state.settings, ...newSettings } }));
}, },
setSettings: async () => { setSettings: async () => {
if (!localStorage.getItem("theme")) { let theme = localStorage.getItem("theme");
localStorage.setItem("theme", "dark"); if (!theme || !theme.includes("-")) {
theme = "default-dark"; // Default theme
localStorage.setItem("theme", theme);
} }
const localTheme = localStorage.getItem("theme") || ""; const localTheme = theme;
document.documentElement.setAttribute('data-theme', localTheme);
if (localTheme.endsWith("-dark")) {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
set((state) => ({ set((state) => ({
settings: { ...state.settings, theme: localTheme }, settings: { ...state.settings, theme: localTheme },
+106 -3
View File
@@ -5,7 +5,7 @@ module.exports = {
daisyui: { daisyui: {
themes: [ themes: [
{ {
light: { "default-light": {
primary: "#0369a1", primary: "#0369a1",
secondary: "#0891b2", secondary: "#0891b2",
accent: "#6d28d9", accent: "#6d28d9",
@@ -21,7 +21,7 @@ module.exports = {
}, },
}, },
{ {
dark: { "default-dark": {
primary: "#7dd3fc", primary: "#7dd3fc",
secondary: "#22d3ee", secondary: "#22d3ee",
accent: "#6d28d9", accent: "#6d28d9",
@@ -36,6 +36,108 @@ module.exports = {
error: "#f1293c", error: "#f1293c",
}, },
}, },
// Red Light Theme
{
"red-light": {
primary: "#ef4444",
secondary: "#dc2626",
accent: "#6d28d9",
neutral: "#6b7280",
"neutral-content": "#d1d5db",
"base-100": "#ffffff",
"base-200": "#f3f4f6",
"base-content": "#0a0a0a",
info: "#a5f3fc",
success: "#22c55e",
warning: "#facc15",
error: "#dc2626",
},
},
// Red Dark Theme
{
"red-dark": {
primary: "#ef4444",
secondary: "#dc2626",
accent: "#6d28d9",
neutral: "#9ca3af",
"neutral-content": "#404040",
"base-100": "#171717",
"base-200": "#262626",
"base-content": "#fafafa",
info: "#009ee4",
success: "#00b17d",
warning: "#eac700",
error: "#f1293c",
},
},
// Green Light Theme
{
"green-light": {
primary: "#22c55e",
secondary: "#16a34a",
accent: "#6d28d9",
neutral: "#6b7280",
"neutral-content": "#d1d5db",
"base-100": "#ffffff",
"base-200": "#f3f4f6",
"base-content": "#0a0a0a",
info: "#a5f3fc",
success: "#22c55e",
warning: "#facc15",
error: "#dc2626",
},
},
// Green Dark Theme
{
"green-dark": {
primary: "#22c55e",
secondary: "#16a34a",
accent: "#6d28d9",
neutral: "#9ca3af",
"neutral-content": "#404040",
"base-100": "#171717",
"base-200": "#262626",
"base-content": "#fafafa",
info: "#009ee4",
success: "#00b17d",
warning: "#eac700",
error: "#f1293c",
},
},
// Orange Light Theme
{
"orange-light": {
primary: "#f97316",
secondary: "#ea580c",
accent: "#6d28d9",
neutral: "#9ca3af",
"neutral-content": "#404040",
"base-100": "#171717",
"base-200": "#262626",
"base-content": "#fafafa",
info: "#009ee4",
success: "#00b17d",
warning: "#eac700",
error: "#f1293c",
},
},
// Orange Dark Theme
{
"orange-dark": {
primary: "#f97316",
secondary: "#ea580c",
accent: "#6d28d9",
neutral: "#9ca3af",
"neutral-content": "#404040",
"base-100": "#171717",
"base-200": "#262626",
"base-content": "#fafafa",
info: "#009ee4",
success: "#00b17d",
warning: "#eac700",
error: "#f1293c",
},
},
], ],
}, },
darkMode: ["class", '[data-theme="dark"]'], darkMode: ["class", '[data-theme="dark"]'],
@@ -53,4 +155,5 @@ module.exports = {
addVariant("dark", '&[data-theme="dark"]'); addVariant("dark", '&[data-theme="dark"]');
}), }),
], ],
}; };
+5
View File
@@ -2714,6 +2714,11 @@ dompurify@^3.0.6:
resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.0.6.tgz#925ebd576d54a9531b5d76f0a5bef32548351dae" resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.0.6.tgz#925ebd576d54a9531b5d76f0a5bef32548351dae"
integrity sha512-ilkD8YEnnGh1zJ240uJsW7AzE+2qpbOUYjacomn3AvJ6J4JhKGSZ2nh4wUIXPZrEPppaCLx5jFe8T89Rk8tQ7w== integrity sha512-ilkD8YEnnGh1zJ240uJsW7AzE+2qpbOUYjacomn3AvJ6J4JhKGSZ2nh4wUIXPZrEPppaCLx5jFe8T89Rk8tQ7w==
dotenv@^16.3.1:
version "16.3.1"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e"
integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==
ecc-jsbn@~0.1.1: ecc-jsbn@~0.1.1:
version "0.1.2" version "0.1.2"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"