v1.0 ready to use

This commit is contained in:
Igor Barcik 2023-12-08 15:39:08 +01:00
parent a0d90aaf79
commit cfe5a813f7
Signed by: biggy
GPG Key ID: EA4CE0D1E2A6DC98
21 changed files with 111 additions and 54 deletions

View File

@ -1,4 +1,4 @@
# TailwindElements-React-Starter
# Universal-React-Starter
- [DaisyUI](https://daisyui.com/) - main styling
- [react-icons](https://react-icons.github.io/react-icons/) - big icon library
@ -11,8 +11,9 @@
## Usage
1. Setup `VITE_APP_NAME` in `.env.{mode}` files
2. run: `bun run dev`
3. To build for production, run: `bun run build`
2. Setup `VITE_BASE_PATH` in `.env.{mode}` files
3. run: `bun run dev`
4. To build for production, run: `bun run build`
_bun can be replaced by packet manager of your choice_

BIN
bun.lockb

Binary file not shown.

View File

@ -1,12 +1,34 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/icon.png" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Fallback title</title>
<!-- SEO Meta Tags -->
<meta name="description" content="Brief description of the page" />
<meta name="keywords" content="keyword1, keyword2, keyword3" />
<meta name="author" content="Author Name" />
<!-- Social Media Meta Tags (Open Graph for Facebook, Twitter Card, etc.) -->
<meta property="og:title" content="Title for Social Media" />
<meta property="og:description" content="Description for Social Media" />
<meta property="og:image" content="URL to image for social media" />
<meta property="og:url" content="URL of the page" />
<meta name="twitter:card" content="summary_large_image" />
<!-- Favicon -->
<link rel="icon" href="/cmms_servimain_logo.png" />
<!-- Additional Tags (like canonical, robots, etc.) -->
<link rel="canonical" href="https://www.example.com/page-url" />
<meta name="robots" content="index, follow" />
<link rel="manifest" href="/manifest.json">
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<script type="module" src="src/main.tsx"></script>
</body>
</html>

View File

@ -4,7 +4,7 @@
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite --host",
"dev": "vite serve",
"build": "tsc && vite build",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview --host"
@ -18,6 +18,7 @@
"axios": "^1.6.1",
"daisyui": "latest",
"echarts": "^5.4.3",
"jotai": "^2.6.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.48.2",

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

21
public/manifest.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "My App",
"short_name": "App",
"icons": [
{
"src": "cmms_servimain_logo_192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "cmms_servimain_logo_512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "/",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 KiB

View File

@ -1,27 +1,32 @@
import ThemeButton from "../components/ThemeButton";
import { main } from "../configure";
import ThemeButton from "./components/ThemeButton";
import { main } from "./configure";
import { Router } from "wouter";
import SwitchRoutesGenerator from "../routes/RouteStructureGenerator";
import DebugNavigationButtonsGenerator from "../routes/DebugNavigationButtonsGenerator";
import SwitchRoutesGenerator from "./routes/SwitchRoutesGenerator";
import GenerateNavigationButtonsDebug from "./routes/GenerateNavigationButtonsDebug";
function App() {
return (
// Router component with base path
<Router base={main.basePath}>
<div className="space-x-4 space-y-6">
<div className="px-5 mt-6">
{/* Displaying program name and version */}
<h1 className="text-center ">
{main.program_name} v{main.program_version}
<p>Base path is: {main.basePath}</p>
</h1>
<div>
{/* ThemeButton component */}
<ThemeButton />
</div>
</div>
{/* Separator */}
<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>
<DebugNavigationButtonsGenerator />
{/* GenerateNavigationButtonsDebug component */}
<GenerateNavigationButtonsDebug />
{/* Paths in Route should be without base path (even without '/'). If want Route for base path than pass base path */}
{/* SwitchRoutesGenerator component */}
<SwitchRoutesGenerator />
</div>
</div>

View File

@ -1,28 +1,21 @@
import { useEffect, useState } from "react";
import { useEffect } 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 isDark = theme === "dark";
const toggleTheme = () => {
console.log("toggleTheme called");
const newTheme = theme === "light" ? "dark" : "light";
setTheme(newTheme);
setIsDark(newTheme === "dark");
document.documentElement.dataset.theme = newTheme;
};
// Apply the theme on component mount
useEffect(() => {
console.log("useEffect called");
document.documentElement.dataset.theme = theme;
}, [theme]); // Re-run effect when theme changes
}, [theme]);
return [isDark, toggleTheme];
};

View File

@ -2,10 +2,11 @@ import React from "react";
import ReactDOM from "react-dom/client";
import { setupAxiosInterceptors } from "./api/AxiosService";
import { viteEnv } from "./configure";
import App from "./features/App";
import App from "./App";
import inDev from "./utils/inDebug";
import { Global, css } from "@emotion/react";
import "/style.css";
import { Provider } from "jotai";
setupAxiosInterceptors();
inDev(() => console.log(viteEnv));
@ -18,6 +19,8 @@ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
// You can add more global styles here
`}
/>
<App />
<Provider>
<App />
</Provider>
</React.StrictMode>,
);

View File

@ -1,7 +1,9 @@
import { useState } from "react";
import { atom, useAtom } from "jotai";
const counterAtom = atom(0);
const HomePage = () => {
const [counter, setCounter] = useState<number>(0);
const [counter, setCounter] = useAtom(counterAtom);
return (
<div>
<p>HomePage</p>

View File

@ -1,7 +1,8 @@
import React from "react";
import * as R from "../routes/routes";
import { v4 } from "uuid";
import { Link } from "wouter";
import { Routes } from "../routes/routes";
import * as R from "./routes";
import { Routes } from "./routes";
import inDev from "../utils/inDebug";
const routesCrawler = (
@ -9,19 +10,18 @@ const routesCrawler = (
routesPack: Routes[] = R.routesRoot,
): JSX.Element[] => {
// Roll through routes and generate Route for each
return routesPack.map((route, index): JSX.Element => {
return routesPack.map((route): JSX.Element => {
// Debug log shows generated routes
inDev(() =>
console.log(
"routesCrawler",
"routesCrawler buttons",
parentPath ? parentPath + route.path : route.path,
),
);
return (
<div className="join">
<div key={v4()} className="join">
{/* Check does route have children and perform routing generation for children */}
<Link
key={index}
className={`btn join-item hover:btn-primary duration-75 `}
href={
parentPath ? parentPath + route.path : route.path != "/" ? route.path : ""
@ -43,8 +43,8 @@ const routesCrawler = (
/**
* This component is used to generate buttons for debug navigation
*/
const DebugNavigationButtonsGenerator = () => {
const GenerateNavigationButtonsDebug = () => {
return <div className="space-y-2 space-x-2 mb-6">{routesCrawler()}</div>;
};
export default DebugNavigationButtonsGenerator;
export default GenerateNavigationButtonsDebug;

View File

@ -1,34 +1,38 @@
import React from "react";
import { v4 } from "uuid";
import { Route, Switch } from "wouter";
import { Routes } from "./routes";
import * as R from "./routes";
import inDev from "../utils/inDebug";
import * as R from "./routes";
import { Routes } from "./routes";
const routesCrawler = (
parentPath?: string,
routesPack: Routes[] = R.routesRoot,
): JSX.Element[] => {
// Roll through routes and generate Route for each
return routesPack.map((route, index): JSX.Element => {
return routesPack.map((route): JSX.Element => {
// Debug log shows generated routes
inDev(() =>
console.log(
"routesCrawler",
"routesCrawler routes",
parentPath ? parentPath + route.path : route.path,
),
);
return (
<>
{/* Check does route have children and perform routing generation for children */}
{route.children
? routesCrawler(parentPath ?? "" + route.path, route.children)
: null}
return route.children ? (
<React.Fragment key={v4()}>
{routesCrawler(parentPath ?? "" + route.path, route.children)}
<Route
key={index}
key={v4()}
path={parentPath ? parentPath + route.path : route.path}
component={route.component}
/>
</>
</React.Fragment>
) : (
<Route
key={v4()}
path={parentPath ? parentPath + route.path : route.path}
component={route.component}
/>
);
});
};
@ -38,7 +42,7 @@ const routesCrawler = (
*/
const SwitchRoutesGenerator = () => {
return (
<Switch>
<Switch key={v4()}>
{routesCrawler()}
<Route component={() => <>404</>} />
</Switch>

View File

@ -3,11 +3,11 @@ import { RiHome3Fill } from "react-icons/ri";
import { IoMdOptions } from "react-icons/io";
import { FaUsers } from "react-icons/fa";
// ----- IMPORT PAGES -----
import AdministrationPage from "../features/AdministrationPage";
import HomePage from "../features/HomePage";
import AdministrationPage from "../pages/AdministrationPage";
import HomePage from "../pages/HomePage";
// ----- IMPORT CONSTS -----
import { ADMINISTRATION, SETTINGS } from "../consts";
import SettingsAdvancedPage from "../features/SettingsAdvancedPage";
import SettingsAdvancedPage from "../pages/SettingsAdvancedPage";
// ----- TYPE DEFINITIONS -----
export type Routes = {

View File

@ -6,5 +6,10 @@ export default ({ mode }) => {
process.env = { ...process.env, ...loadEnv(mode, process.cwd()) };
return defineConfig({
plugins: [react()],
build: {
watch: {
clearScreen: true,
},
},
});
};