Big comeback to DaisyUI, removed other stuff

This commit is contained in:
Igor Barcik 2023-11-14 13:53:59 +01:00
parent 82e0b21c06
commit 8ea78084c9
Signed by: biggy
GPG Key ID: EA4CE0D1E2A6DC98
15 changed files with 3165 additions and 103 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en">
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

View File

@ -10,9 +10,14 @@
"preview": "vite preview --host"
},
"dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@hookform/resolvers": "^3.3.2",
"@tailwindcss/forms": "^0.5.7",
"@tanstack/react-table": "^8.10.7",
"appwrite": "^13.0.0",
"axios": "^1.6.1",
"daisyui": "latest",
"echarts": "^5.4.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@ -38,7 +43,7 @@
"eslint-plugin-react-refresh": "^0.4.4",
"postcss": "^8.4.31",
"postcss-simple-vars": "^7.0.1",
"prettier": "^3.0.3",
"prettier": "^3.1.0",
"tailwindcss": "^3.3.5",
"typescript": "^5.2.2",
"vite": "^4.5.0"

3000
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,7 @@
export default {
plugins: {
"postcss-import": {},
"tailwindcss/nesting": {},
tailwindcss: {},
autoprefixer: {},
},

BIN
public/pattern.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 KiB

View File

@ -0,0 +1,33 @@
import useTheme from "../hooks/useTheme";
import inDev from "../utils/inDebug";
const ThemeButton = () => {
const [isDark, toggleTheme] = useTheme();
return (
<label className="swap swap-rotate btn btn-outline btn-circle">
<input
checked={isDark}
className="hidden"
onChange={() => inDev(() => console.log("Theme changed"))}
onClick={toggleTheme}
type="checkbox"
/>
<svg
className="swap-on fill-current w-6 h-6"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
</svg>
<svg
className="swap-off fill-current w-6 h-6"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
>
<path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z" />
</svg>
</label>
);
};
export default ThemeButton;

View File

@ -1,3 +1,4 @@
// -------- ENVIRONMENT VARIABLES --------
export const viteEnv = import.meta.env;
//Main configuration, static data, mostly used here
export const main = {
@ -11,3 +12,7 @@ export const about = {
program_description: `This is a ${main.program_name} for <purpose>.`,
program_authors: [{ name: "Author Name", email: "email@example.com" }],
};
// -------- FRONTEND CONFIGURATION --------
// sizes in pixels
export const topbarSize = 64;
export const sidebarSize = 256;

View File

@ -1,15 +1,19 @@
import ThemeButton from "../components/ThemeButton";
import { main } from "../configure";
function App() {
return (
<>
{main.program_name} v{main.program_version}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc magna massa,
ornare quis interdum a, cursus in quam. Quisque risus libero, cursus eget
eros vitae, aliquam placerat velit. Vivamus luctus eros id sagittis luctus.
Pellentesque felis nulla, rhoncus viverra nunc vitae, viverra aliquam ante.
Ut feugiat mattis tempor.
</>
<div className="space-x-4 space-y-6 m-4">
<div className="px-5 mt-6">
<h1 className="text-center ">
{main.program_name} v{main.program_version}
</h1>
<div>
<ThemeButton />
</div>
</div>
<hr className="my-12 h-[2px] border-t-0 bg-transparent bg-gradient-to-r from-transparent via-current to-transparent opacity-25 dark:opacity-100" />
</div>
);
}

View File

@ -0,0 +1,35 @@
import { useState } from "react";
/**
* Works like useState but stores the value in local storage
* @param key Create a key to store the value in local storage
* @param initialValue Assign an initial value to the key
* @returns [storedValue, setValue] Returns the stored value and a function to set the value
*/
const useLocalStorage = <T>(
key: string,
initialValue: T,
): [T, (value: T) => void] => {
const [storedValue, setStoredValue] = useState<T>(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.log(error);
return initialValue;
}
});
const setValue = (value: T) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.log(error);
}
};
return [storedValue, setValue];
};
export default useLocalStorage;

30
src/hooks/useTheme.ts Normal file
View File

@ -0,0 +1,30 @@
import { useEffect, useState } from "react";
import useLocalStorage from "./useLocalStorage";
/**
* A hook to toggle between light and dark theme and store the value in local storage.
* @returns {isDark, toggleTheme} - Returns a boolean indicating if dark mode is active and a function to toggle the theme.
*/
const useTheme = (): [boolean, () => void] => {
// Initialize theme from local storage or default value
const [theme, setTheme] = useLocalStorage<string>("theme", "light");
// Determine if the current theme is dark
const [isDark, setIsDark] = useState<boolean>(theme === "dark");
const toggleTheme = () => {
const newTheme = theme === "light" ? "dark" : "light";
setTheme(newTheme);
setIsDark(newTheme === "dark");
document.documentElement.dataset.theme = newTheme;
};
// Apply the theme on component mount
useEffect(() => {
document.documentElement.dataset.theme = theme;
}, [theme]); // Re-run effect when theme changes
return [isDark, toggleTheme];
};
export default useTheme;

View File

@ -4,6 +4,7 @@ import { setupAxiosInterceptors } from "./api/AxiosService";
import { viteEnv } from "./configure";
import App from "./features/App";
import inDev from "./utils/inDebug";
import { Global, css } from "@emotion/react";
setupAxiosInterceptors();
inDev(() => console.log(viteEnv));
@ -11,6 +12,11 @@ inDev(() => console.log(viteEnv));
// Hook react to the HTML element with id="root"
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<Global
styles={css`
// You can add more global styles here
`}
/>
<App />
</React.StrictMode>,
);

View File

@ -1,79 +0,0 @@
import {
CustomRouteObject,
RouteObjectAdditionalProps,
flatRoutes,
} from "../configure";
import {
clearMultiplePathSlashes,
trimPathOfParameters,
} from "./StringTransformationUtils";
interface FlatternRoutingTableElement extends RouteObjectAdditionalProps {
path: string;
name: string;
}
//! WARNING: This function will generate error if paths aren't unique, disableInNavbar or disableRedirect to prevent this. It's a useful feature to prevent duplicate path in navbar
/**
* @description Convert a existing routing table as a flat array
*/
export const flatternRoutingTable = (
routes: CustomRouteObject[],
previousPath = "undefined",
): FlatternRoutingTableElement[] => {
const result: FlatternRoutingTableElement[] = [];
routes.forEach((route: CustomRouteObject) => {
if (route.additionalProps.disableRedirect) return; // Skip if disable redirect, children are skipped too
if (
typeof route.path !== "undefined" &&
typeof previousPath === "undefined" &&
!route.additionalProps.disableInNavbar
) {
result.push({
path: trimPathOfParameters(route.path),
name: route.additionalProps.name,
disableBreadcrumbBar: route.additionalProps.disableBreadcrumbBar,
disableInNavbar: route.additionalProps.disableInNavbar,
disableRedirect: route.additionalProps.disableRedirect,
});
}
if (
typeof route.path !== "undefined" &&
typeof previousPath !== "undefined" &&
!route.additionalProps.disableInNavbar
) {
result.push({
path: trimPathOfParameters(
clearMultiplePathSlashes(`/${previousPath}/${route.path}`),
),
name: route.additionalProps.name,
disableBreadcrumbBar: route.additionalProps.disableBreadcrumbBar,
disableInNavbar: route.additionalProps.disableInNavbar,
disableRedirect: route.additionalProps.disableRedirect,
});
}
if (route.children && typeof previousPath === "undefined") {
result.push(...flatternRoutingTable(route.children));
}
if (route.children && typeof previousPath !== "undefined") {
result.push(...flatternRoutingTable(route.children, route.path));
}
// Errors handling
if (typeof route.path === "undefined")
console.error(`Route ${route.additionalProps.name} is missing path`);
});
return result;
};
/**
* @description Function to find element in flattern routes array by LAST path ex: /admin/MAINTENANCE
*/
export const findElementInFlatRoutes = (
path: string,
): FlatternRoutingTableElement | undefined => {
// Split path string into array, split by '/', then get the last element
const _route = flatRoutes.find((route) => {
const pathArray = route.path.split("/");
if (pathArray[pathArray.length - 1] === path) return true;
else return false;
});
return _route;
};

View File

@ -1,15 +1,3 @@
@import url("https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900&display=swap");
@tailwind base;
@layer base {
html {
@apply text-neutral-800;
}
html.dark {
@apply text-neutral-50;
@apply bg-neutral-800;
}
}
@tailwind components;
@tailwind utilities;

View File

@ -1,7 +1,40 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ["./src/**/*.{js,ts,jsx,tsx}", "./index.html"],
// safelist is used to allow classes to not be purged by tailwind
safelist: ["alert-info", "alert-success", "alert-warning", "alert-error"],
plugins: [require("@tailwindcss/typography")],
theme: {
extend: {
spacing: {
128: "32rem",
144: "36rem",
},
borderRadius: {
"4xl": "2rem",
},
},
},
darkMode: "class",
plugins: [
require("@tailwindcss/typography"),
require("@tailwindcss/forms"),
require("daisyui"),
],
daisyui: {
themes: [
{
light: {
primary: "#38bdf8",
secondary: "#10b981",
accent: "#f59e0b",
neutral: "#e5e7eb",
"base-100": "#f3f4f6",
info: "#67e8f9",
success: "#6ee7b7",
warning: "#fde047",
error: "#f87171",
},
},
"dark",
],
},
};