diff --git a/index.html b/index.html index e4b78ea..12834a1 100644 --- a/index.html +++ b/index.html @@ -2,9 +2,9 @@ - + - Vite + React + TS + Kedai Susu Tuli - SIBI
diff --git a/package-lock.json b/package-lock.json index c0ab93a..a7783cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,11 +8,16 @@ "name": "ksuli-sibi", "version": "0.0.0", "dependencies": { + "clsx": "^2.1.1", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-icons": "^5.3.0", + "tailwind-merge": "^2.5.2", + "zustand": "^4.5.5" }, "devDependencies": { "@eslint/js": "^9.9.0", + "@types/node": "^22.4.2", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.1", @@ -1234,17 +1239,26 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/@types/node": { + "version": "22.4.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.4.2.tgz", + "integrity": "sha512-nAvM3Ey230/XzxtyDcJ+VjvlzpzoHwLsF7JaDRfoI0ytO0mVheerNmM45CtA0yOILXwXXxOrcUWH3wltX+7PSw==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true + "devOptional": true }, "node_modules/@types/react": { "version": "18.3.4", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.4.tgz", "integrity": "sha512-J7W30FTdfCxDDjmfRM+/JqLHBIyl7xUIp9kwK637FGmY7+mkSFSe6L4jpZzhj5QMfLssSDP4/i75AKkrdC7/Jw==", - "dev": true, + "devOptional": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -1803,6 +1817,14 @@ "node": ">= 6" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -1879,7 +1901,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true + "devOptional": true }, "node_modules/culori": { "version": "3.3.0", @@ -3349,6 +3371,14 @@ "react": "^18.3.1" } }, + "node_modules/react-icons": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz", + "integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-refresh": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", @@ -3689,6 +3719,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tailwind-merge": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.2.tgz", + "integrity": "sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, "node_modules/tailwindcss": { "version": "3.4.10", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.10.tgz", @@ -3840,6 +3879,12 @@ } } }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + }, "node_modules/update-browserslist-db": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", @@ -3879,6 +3924,14 @@ "punycode": "^2.1.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -4124,6 +4177,33 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.5.tgz", + "integrity": "sha512-+0PALYNJNgK6hldkgDq2vLrw5f6g/jCInz52n9RTpropGgeAf/ioFUCdtsjCqu4gNhW9D01rUQBROoRjdzyn2Q==", + "dependencies": { + "use-sync-external-store": "1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } } } } diff --git a/package.json b/package.json index f309ca2..e5c63d4 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,16 @@ "preview": "vite preview" }, "dependencies": { + "clsx": "^2.1.1", "react": "^18.3.1", - "react-dom": "^18.3.1" + "react-dom": "^18.3.1", + "react-icons": "^5.3.0", + "tailwind-merge": "^2.5.2", + "zustand": "^4.5.5" }, "devDependencies": { "@eslint/js": "^9.9.0", + "@types/node": "^22.4.2", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react": "^4.3.1", diff --git a/public/assets/images/logo.png b/public/assets/images/logo.png new file mode 100644 index 0000000..3b860c7 Binary files /dev/null and b/public/assets/images/logo.png differ diff --git a/src/App.tsx b/src/App.tsx index 3a31e76..ea0d98b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,11 @@ +import LayoutPage from "./components/templates/LayoutPage"; const App = () => { - return
Hello World
; + return ( + +

Hello World

+
+ ); }; export default App; diff --git a/src/components/molecules/NavLink.tsx b/src/components/molecules/NavLink.tsx new file mode 100644 index 0000000..d0b11d9 --- /dev/null +++ b/src/components/molecules/NavLink.tsx @@ -0,0 +1,24 @@ +import { cn } from "@/lib/utils"; + +type NavLinkProps = { + href: string; + name: string; + isActive: boolean; +}; + +const NavLink = ({ href, name, isActive }: NavLinkProps) => { + return ( + +
  • + {name} +
  • +
    + ); +}; + +export default NavLink; diff --git a/src/components/organisms/FooterPage.tsx b/src/components/organisms/FooterPage.tsx new file mode 100644 index 0000000..6668e8f --- /dev/null +++ b/src/components/organisms/FooterPage.tsx @@ -0,0 +1,14 @@ +const FooterPage = () => { + return ( + + ); +}; + +export default FooterPage; diff --git a/src/components/organisms/HeaderPage.tsx b/src/components/organisms/HeaderPage.tsx new file mode 100644 index 0000000..5096784 --- /dev/null +++ b/src/components/organisms/HeaderPage.tsx @@ -0,0 +1,51 @@ +import useNavbarStore from "@/stores/NavbarStore"; +import { cn } from "@lib/utils"; +import { IoClose } from "react-icons/io5"; +import { RxHamburgerMenu } from "react-icons/rx"; +import NavLink from "../molecules/NavLink"; + +const HeaderPage = () => { + const navStore = useNavbarStore(); + return ( +
    +
    +
    + Logo Kedai Susu Tuli +
    +

    K-SULI

    +

    Kedai Susu Tuli

    +
    +
    + + +
    +
    + ); +}; + +export default HeaderPage; diff --git a/src/components/templates/LayoutPage.tsx b/src/components/templates/LayoutPage.tsx new file mode 100644 index 0000000..2e101d2 --- /dev/null +++ b/src/components/templates/LayoutPage.tsx @@ -0,0 +1,17 @@ +import React from "react"; +import HeaderPage from "../organisms/HeaderPage"; +import FooterPage from "../organisms/FooterPage"; + +const LayoutPage = ({ children }: { children: React.ReactNode }) => { + return ( +
    + +
    + {children} +
    + +
    + ); +}; + +export default LayoutPage; diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..d084cca --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/src/stores/NavbarStore.ts b/src/stores/NavbarStore.ts new file mode 100644 index 0000000..5181556 --- /dev/null +++ b/src/stores/NavbarStore.ts @@ -0,0 +1,13 @@ +import { create } from "zustand"; + +type NavbarType = { + isOpen: boolean; + toggle: () => void; +}; + +const useNavbarStore = create((set) => ({ + isOpen: false, + toggle: () => set((state) => ({ isOpen: !state.isOpen })), +})); + +export default useNavbarStore; diff --git a/tailwind.config.js b/tailwind.config.js index 691efea..c8b99a4 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -2,7 +2,32 @@ export default { content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], theme: { - extend: {}, + extend: { + container: { + center: true, + padding: "1rem", + }, + colors: { + ground: "#FAF7EE", + }, + }, + }, + daisyui: { + themes: [ + { + mytheme: { + primary: "#fbbf24", + secondary: "#00b44a", + accent: "#0099db", + neutral: "#080f0e", + "base-100": "#f3f4f6", + info: "#00abf0", + success: "#00e5ab", + warning: "#fb923c", + error: "#e11d48", + }, + }, + ], }, plugins: [require("daisyui")], }; diff --git a/tsconfig.app.json b/tsconfig.app.json index f0a2350..9d20443 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -18,7 +18,15 @@ "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + + /* Aliases */ + "baseUrl": ".", + "paths": { + "@/*": ["src/*"], + "@components/*": ["src/components/*"], + "@lib/*": ["src/lib/*"] + } }, "include": ["src"] } diff --git a/vite.config.ts b/vite.config.ts index 5a33944..c271af4 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,15 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import path from "path"; // https://vitejs.dev/config/ export default defineConfig({ + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + "@components": path.resolve(__dirname, "./src/components"), + "@lib": path.resolve(__dirname, "./src/lib"), + }, + }, plugins: [react()], -}) +});