From b6fec8038b854a47474baacad5bb50b6b3e7db8f Mon Sep 17 00:00:00 2001 From: 0xsuxin <709228919@qq.com> Date: Mon, 29 Jul 2024 17:11:00 +0800 Subject: [PATCH 1/2] task1: 0xsuxin --- members/0xsuxin/task1/README.md | 113 +++++++++++ members/0xsuxin/task1/index.html | 13 ++ members/0xsuxin/task1/package.json | 47 +++++ members/0xsuxin/task1/postcss.config.js | 7 + members/0xsuxin/task1/renovate.json | 14 ++ .../task1/src/components/Header/index.tsx | 9 + .../task1/src/components/ToDoItem/index.tsx | 10 + .../task1/src/components/ToDoList/index.tsx | 179 ++++++++++++++++++ .../0xsuxin/task1/src/components/root/App.tsx | 17 ++ .../task1/src/components/root/Main.tsx | 25 +++ .../task1/src/components/router/Router.tsx | 52 +++++ members/0xsuxin/task1/src/favicon.svg | 15 ++ members/0xsuxin/task1/src/index.css | 17 ++ members/0xsuxin/task1/src/lib/firebase.ts | 55 ++++++ members/0xsuxin/task1/src/logo.svg | 7 + members/0xsuxin/task1/src/main.tsx | 15 ++ members/0xsuxin/task1/src/styles/arrow.css | 34 ++++ members/0xsuxin/task1/src/vite-env.d.ts | 16 ++ members/0xsuxin/task1/tailwind.config.js | 31 +++ members/0xsuxin/task1/tsconfig.json | 26 +++ members/0xsuxin/task1/vite.config.ts | 8 + 21 files changed, 710 insertions(+) create mode 100644 members/0xsuxin/task1/README.md create mode 100644 members/0xsuxin/task1/index.html create mode 100644 members/0xsuxin/task1/package.json create mode 100644 members/0xsuxin/task1/postcss.config.js create mode 100644 members/0xsuxin/task1/renovate.json create mode 100644 members/0xsuxin/task1/src/components/Header/index.tsx create mode 100644 members/0xsuxin/task1/src/components/ToDoItem/index.tsx create mode 100644 members/0xsuxin/task1/src/components/ToDoList/index.tsx create mode 100644 members/0xsuxin/task1/src/components/root/App.tsx create mode 100644 members/0xsuxin/task1/src/components/root/Main.tsx create mode 100644 members/0xsuxin/task1/src/components/router/Router.tsx create mode 100644 members/0xsuxin/task1/src/favicon.svg create mode 100644 members/0xsuxin/task1/src/index.css create mode 100644 members/0xsuxin/task1/src/lib/firebase.ts create mode 100644 members/0xsuxin/task1/src/logo.svg create mode 100644 members/0xsuxin/task1/src/main.tsx create mode 100644 members/0xsuxin/task1/src/styles/arrow.css create mode 100644 members/0xsuxin/task1/src/vite-env.d.ts create mode 100644 members/0xsuxin/task1/tailwind.config.js create mode 100644 members/0xsuxin/task1/tsconfig.json create mode 100644 members/0xsuxin/task1/vite.config.ts diff --git a/members/0xsuxin/task1/README.md b/members/0xsuxin/task1/README.md new file mode 100644 index 000000000..78db273da --- /dev/null +++ b/members/0xsuxin/task1/README.md @@ -0,0 +1,113 @@ +# ⚡ vite-react-ts-tailwind-starter + +Starter using Vite + React + TypeScript + Tailwind with Firebase. + +## Motivation + +Improve building your faster **prototyping** by using Vite, TypeScript, React, TailwindCSS, Firebase. + +This starter uses following libraries: + +- Vite +- React + - React Router +- TypeScript +- Tailwind CSS + - daisyUI +- Firebase(v9, modular) +- ESLint +- Prettier + +## Set up + +```shell +mv .env.local.example .env.local +yarn +yarn dev +``` + +### Firebase + +If you **DO NOT** use Firebase, you should do: + +- Delete the Firebase-related code: you check Main.tsx, SignInButton.tsx, SignOutButton.tsx. +- And then delete `src/lib/firebase.ts` +- Run `yarn remove firebase` +- Remove `VITE_FIREBASE_*` env values from `.env.local` + +If you want to use Firebase, you should do: + +- copy Firebase env values from Firebase Console, and paste them to `.env.local`. +- enable Google Auth in Firebase Console. ref: https://firebase.google.com/docs/auth/web/google-signin#before_you_begin + +## Vite + +[Vite](https://github.com/vitejs/vite) is a fast frontend build tool. According to the [README](https://github.com/vitejs/vite/blob/main/README.md), it consists of two major parts: + +- A dev server that serves your source files over native ES modules, with rich built-in features and astonishingly fast Hot Module Replacement (HMR). +- A build command that bundles your code with Rollup, pre-configured to output highly optimized static assets for production. + +## React + +[React](https://github.com/facebook/react) is a JavaScript library for building user interfaces. + +Due to its awesome renderer system, there are many [React Renderor](https://github.com/chentsulin/awesome-react-renderer). So React can be not used only Web, for example, used by [React Native](https://reactnative.dev/). + +Let's dive into React and Vite can use with React. + +## TypeScript + +[TypeScript](https://github.com/microsoft/TypeScript) is a superset of JavaScript. It is just one of NPM library, but it provides an original compiler. + +When you use TypeScript with React, you can write JSX with TypeScript, called TSX. Then you can develop views written by **Type-Safe** template. + +## Tailwind CSS + +[Tailwind CSS](https://tailwindcss.com/) is modern utility-first CSS framework. It provides many CSS rules, but these are purged when production builds. So developers do not worry about CSS asset size for performance optimization. + +In VSCode, I recommend to use [intellisense extension](https://tailwindcss.com/docs/intellisense). + +Frequently, React developers are worried about how to write CSS in TSX(JSX) template. You must choose from CSS Modules, [styled-components](https://styled-components.com/), [linaria](https://github.com/callstack/linaria), and so on. +Additionally, CSS architecture is difficult about scoping, e.g. BEM, FLOCSS. + +When you decide to use Tailwind, you only write utility-first CSS classes, you don't have to worry about them! + +### daisyUI + +[daisyUI](https://daisyui.com/) is Tailwind CSS Components library. + +It prepares components CSS classes such as 'btn'. If you provide 'btn' class to ` + + + ), + }, + ]; + + useEffect(() => { + // 获取数据 + const todoList = store2('todoList'); + if (todoList?.length) { + setData(todoList); + } + return () => { + store2('todoList', todoList); + }; + }, []); + + return ( + <> +
+ +
+ + + +
+ { + const todoList = data; + if (todoList.some((v) => v.name === value)) { + return Promise.reject(new Error('待办事件已存在')); + } + if (!value) { + return Promise.reject(new Error('请输入待办事件名称')); + } + return Promise.resolve(); + }, + }, + ]} + > + + + +
+ + ); +} + +export default ToDoList; diff --git a/members/0xsuxin/task1/src/components/root/App.tsx b/members/0xsuxin/task1/src/components/root/App.tsx new file mode 100644 index 000000000..ae920d7c3 --- /dev/null +++ b/members/0xsuxin/task1/src/components/root/App.tsx @@ -0,0 +1,17 @@ +import { Col, Divider, Row } from 'antd'; +import Header from '../Header/index.tsx'; +import ToDoList from '../ToDoList/index'; + +export function App() { + return ( +
+ +
+
+ + + + + + ); +} diff --git a/members/0xsuxin/task1/src/components/root/Main.tsx b/members/0xsuxin/task1/src/components/root/Main.tsx new file mode 100644 index 000000000..4311b159f --- /dev/null +++ b/members/0xsuxin/task1/src/components/root/Main.tsx @@ -0,0 +1,25 @@ +import { Router } from "~/components/router/Router"; +import { useEffect } from "react"; +function Main() { + // const { signIn } = useSignIn(); + // const { signOut } = useSignOut(); + useEffect(() => { + + // const auth = getAuth(); + + // onAuthStateChanged(auth, (user) => { + // if (user) { + // signIn(user); + // } else { + // signOut(); + // } + // }); + }, []); + return ( +
+ +
+ ); +} + +export default Main; diff --git a/members/0xsuxin/task1/src/components/router/Router.tsx b/members/0xsuxin/task1/src/components/router/Router.tsx new file mode 100644 index 000000000..f0506c3a4 --- /dev/null +++ b/members/0xsuxin/task1/src/components/router/Router.tsx @@ -0,0 +1,52 @@ +import { Dialog } from '@headlessui/react'; +import { lazy, Suspense, useState } from 'react'; +import { Outlet, RouteObject, useRoutes, BrowserRouter } from 'react-router-dom'; + +const Loading = () =>

Loading...

; + +const IndexScreen = lazy(() => import('~/components/screens/Index')); +const Page404Screen = lazy(() => import('~/components/screens/404')); + +function Layout() { + return ( +
+ + +
+ ); +} + +export const Router = () => { + return ( + + + + ); +}; + +const InnerRouter = () => { + const routes: RouteObject[] = [ + { + path: '/', + element: , + children: [ + { + index: true, + element: , + }, + { + path: '*', + element: , + }, + ], + }, + ]; + const element = useRoutes(routes); + return ( +
+ }>{element} +
+ ); +}; diff --git a/members/0xsuxin/task1/src/favicon.svg b/members/0xsuxin/task1/src/favicon.svg new file mode 100644 index 000000000..de4aeddc1 --- /dev/null +++ b/members/0xsuxin/task1/src/favicon.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/members/0xsuxin/task1/src/index.css b/members/0xsuxin/task1/src/index.css new file mode 100644 index 000000000..17df0e7ec --- /dev/null +++ b/members/0xsuxin/task1/src/index.css @@ -0,0 +1,17 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +body { + margin: 0; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + monospace; +} diff --git a/members/0xsuxin/task1/src/lib/firebase.ts b/members/0xsuxin/task1/src/lib/firebase.ts new file mode 100644 index 000000000..b14414db8 --- /dev/null +++ b/members/0xsuxin/task1/src/lib/firebase.ts @@ -0,0 +1,55 @@ +import { FirebaseApp, initializeApp } from 'firebase/app'; +import { getAuth, Auth, connectAuthEmulator } from 'firebase/auth'; +import { connectFirestoreEmulator, getFirestore } from "firebase/firestore"; +import { connectStorageEmulator, getStorage } from "firebase/storage"; + +let firebaseApp: FirebaseApp; +const useEmulator = () => import.meta.env.VITE_USE_FIREBASE_EMULATOR; + +export const setupFirebase = () => { + try { + firebaseApp = initializeApp({ + apiKey: import.meta.env.VITE_FIREBASE_APIKEY, + authDomain: import.meta.env.VITE_FIREBASE_AUTHDOMAIN, + databaseURL: import.meta.env.VITE_FIREBASE_DATABASEURL, + projectId: import.meta.env.VITE_FIREBASE_PROJECTID, + storageBucket: import.meta.env.VITE_FIREBASE_STORAGEBUCKET, + messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGINGSENDERID, + appId: import.meta.env.VITE_FIREBASE_APPID, + }); + } catch (error) { + console.error({error}) + } +}; + +let auth: Auth; +let firestore: ReturnType; +let storage: ReturnType; + +export const useAuth = () => { + auth = getAuth(firebaseApp); + if (useEmulator()) { + connectAuthEmulator(auth, 'http://localhost:9099'); + } + return auth; +}; + +export const useFirestore = () => { + if (!firestore) { + firestore = getFirestore(); + if (useEmulator()) { + connectFirestoreEmulator(firestore, 'localhost', 8080); + } + } + return firestore; +}; + +export const useStorage = () => { + if (!storage) { + storage = getStorage(); + if (useEmulator()) { + connectStorageEmulator(storage, 'localhost', 9199); + } + } + return storage; +}; diff --git a/members/0xsuxin/task1/src/logo.svg b/members/0xsuxin/task1/src/logo.svg new file mode 100644 index 000000000..6b60c1042 --- /dev/null +++ b/members/0xsuxin/task1/src/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/members/0xsuxin/task1/src/main.tsx b/members/0xsuxin/task1/src/main.tsx new file mode 100644 index 000000000..a42f03a21 --- /dev/null +++ b/members/0xsuxin/task1/src/main.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import "./index.css"; +import { App } from "~/components/root/App"; +import { createRoot } from 'react-dom/client'; + +// ReactDOM.render( +// +// +// , +// document.getElementById("root") +// ); + +const container = document.getElementById('root'); +const root = createRoot(container); // createRoot(container!) if you use TypeScript +root.render(); diff --git a/members/0xsuxin/task1/src/styles/arrow.css b/members/0xsuxin/task1/src/styles/arrow.css new file mode 100644 index 000000000..17bc41f1b --- /dev/null +++ b/members/0xsuxin/task1/src/styles/arrow.css @@ -0,0 +1,34 @@ +.arrow { + width: 100%; + height: 0; + border-top: 2px solid #333; + position: relative; +} + +.arrow::after { + position: absolute; + content: ''; + display: block; +} + +.arrow:not(.left)::after { + top: -2px; + right: 0; + width: 12px; + height: 12px; + border-top: 2px solid #333; + border-right: 2px solid #333; + transform: rotate(45deg); + transform-origin: top right; +} + +.arrow.left::after { + top: -2px; + left: 0; + width: 12px; + height: 12px; + border-top: 2px solid #333; + border-left: 2px solid #333; + transform: rotate(-45deg); + transform-origin: top left; +} diff --git a/members/0xsuxin/task1/src/vite-env.d.ts b/members/0xsuxin/task1/src/vite-env.d.ts new file mode 100644 index 000000000..213c80593 --- /dev/null +++ b/members/0xsuxin/task1/src/vite-env.d.ts @@ -0,0 +1,16 @@ +/// + +interface ImportMetaEnv { + MODE: string; + VITE_SERVICE_NAME: string + VITE_FIREBASE_APIKEY: string; + VITE_FIREBASE_AUTHDOMAIN: string; + VITE_FIREBASE_DATABASEURL: string; + VITE_FIREBASE_PROJECTID: string; + VITE_FIREBASE_STORAGEBUCKET: string; + VITE_FIREBASE_MESSAGINGSENDERID: string; + VITE_FIREBASE_APPID: string; + VITE_FIREBASE_MEASUREMENTID: string; + VITE_USE_FIREBASE_EMULATOR: string; + VITE_API_ORIGIN: string; +} diff --git a/members/0xsuxin/task1/tailwind.config.js b/members/0xsuxin/task1/tailwind.config.js new file mode 100644 index 000000000..d30c9a8b5 --- /dev/null +++ b/members/0xsuxin/task1/tailwind.config.js @@ -0,0 +1,31 @@ + +module.exports = { + mode: 'jit', + purge: { + enabled: process.env.NODE_ENV === 'production', + safeList: [], + content: ['./index.html', './src/**/*.tsx', './src/**/*.ts'], + }, + theme: { + minWidth: { + '40': '10rem', + '60': '15rem', + '80': '20rem', + '100': '25rem', + }, + maxWidth: { + '120': '30rem', + '160': '40rem', + '200': '50rem', + } + }, + variants: {}, + plugins: [ + require('daisyui'), + ], + daisyui: { + themes: [ + 'emerald' + ], + } +} diff --git a/members/0xsuxin/task1/tsconfig.json b/members/0xsuxin/task1/tsconfig.json new file mode 100644 index 000000000..a5a3c3eb3 --- /dev/null +++ b/members/0xsuxin/task1/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "types": ["vite/client"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "baseUrl": "./src", + "paths": { + "~/*": [ + "./*" + ] + } + }, + "include": ["./src"] +} diff --git a/members/0xsuxin/task1/vite.config.ts b/members/0xsuxin/task1/vite.config.ts new file mode 100644 index 000000000..cf4b187a3 --- /dev/null +++ b/members/0xsuxin/task1/vite.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import tsconfigPaths from 'vite-tsconfig-paths'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tsconfigPaths()] +}) From 185903bbc806203d71e24671ee12cd4fb56f1fb2 Mon Sep 17 00:00:00 2001 From: 0xsuxin <709228919@qq.com> Date: Tue, 30 Jul 2024 12:02:01 +0800 Subject: [PATCH 2/2] task1: 0xsuxin --- members/0xsuxin/task1/src/components/ToDoList/index.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/members/0xsuxin/task1/src/components/ToDoList/index.tsx b/members/0xsuxin/task1/src/components/ToDoList/index.tsx index adf6d293b..1d7f5dc91 100644 --- a/members/0xsuxin/task1/src/components/ToDoList/index.tsx +++ b/members/0xsuxin/task1/src/components/ToDoList/index.tsx @@ -133,8 +133,14 @@ function ToDoList() { if (todoList?.length) { setData(todoList); } + const handle = () => { + setData((value) => { + store2('todoList', value); + }); + }; + window.addEventListener('beforeunload', handle); return () => { - store2('todoList', todoList); + window.removeEventListener('beforeunload', handle); }; }, []);