diff --git a/client/packages/rtc-web/.eslintrc.cjs b/client/packages/rtc-web/.eslintrc.cjs index 574cae5..503f1af 100644 --- a/client/packages/rtc-web/.eslintrc.cjs +++ b/client/packages/rtc-web/.eslintrc.cjs @@ -20,5 +20,6 @@ module.exports = { rules: { indent: ['error', 2], semi: ['error', 'always'], + 'vue/attribute-hyphenation': 'off', }, }; diff --git a/client/packages/rtc-web/index.html b/client/packages/rtc-web/index.html index 143557b..c92fabd 100644 --- a/client/packages/rtc-web/index.html +++ b/client/packages/rtc-web/index.html @@ -4,7 +4,7 @@ - Vite + Vue + TS + Rtc
diff --git a/client/packages/rtc-web/package.json b/client/packages/rtc-web/package.json index e67e947..05138df 100644 --- a/client/packages/rtc-web/package.json +++ b/client/packages/rtc-web/package.json @@ -9,7 +9,10 @@ }, "dependencies": { "@vitejs/plugin-vue-jsx": "^3.0.1", - "vue": "^3.3.4" + "@vueuse/core": "^10.2.0", + "theme-change": "^2.5.0", + "vue": "^3.3.4", + "vue-router": "4" }, "devDependencies": { "@types/node": "^20.3.1", diff --git a/client/packages/rtc-web/src/App.vue b/client/packages/rtc-web/src/App.vue index a7d8731..8853cc7 100644 --- a/client/packages/rtc-web/src/App.vue +++ b/client/packages/rtc-web/src/App.vue @@ -2,6 +2,7 @@ import Layout from '@/layout/index.vue'; + diff --git a/client/packages/rtc-web/src/assets/svg-icon/github.svg b/client/packages/rtc-web/src/assets/svg-icon/github.svg new file mode 100644 index 0000000..83901c3 --- /dev/null +++ b/client/packages/rtc-web/src/assets/svg-icon/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/packages/rtc-web/src/assets/svg-icon/moon.svg b/client/packages/rtc-web/src/assets/svg-icon/moon.svg new file mode 100644 index 0000000..17e0c9a --- /dev/null +++ b/client/packages/rtc-web/src/assets/svg-icon/moon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/packages/rtc-web/src/assets/svg-icon/sun.svg b/client/packages/rtc-web/src/assets/svg-icon/sun.svg new file mode 100644 index 0000000..476d5b2 --- /dev/null +++ b/client/packages/rtc-web/src/assets/svg-icon/sun.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/packages/rtc-web/src/components/base/index.ts b/client/packages/rtc-web/src/components/base/index.ts index 707bf95..bfc3e31 100644 --- a/client/packages/rtc-web/src/components/base/index.ts +++ b/client/packages/rtc-web/src/components/base/index.ts @@ -1,2 +1,3 @@ export { default as SvgIcon } from './svg-icon.vue'; export { default as MenuSide } from './menu-side.vue'; +export { default as NavIcons } from './nav-icons.vue'; diff --git a/client/packages/rtc-web/src/components/base/nav-icons.vue b/client/packages/rtc-web/src/components/base/nav-icons.vue new file mode 100644 index 0000000..e849f7d --- /dev/null +++ b/client/packages/rtc-web/src/components/base/nav-icons.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/client/packages/rtc-web/src/components/base/svg-icon.vue b/client/packages/rtc-web/src/components/base/svg-icon.vue index d655b53..e540b3d 100644 --- a/client/packages/rtc-web/src/components/base/svg-icon.vue +++ b/client/packages/rtc-web/src/components/base/svg-icon.vue @@ -1,10 +1,11 @@ + + diff --git a/client/packages/rtc-web/src/components/lib.tsx b/client/packages/rtc-web/src/components/lib.tsx index ea36580..efb1082 100644 --- a/client/packages/rtc-web/src/components/lib.tsx +++ b/client/packages/rtc-web/src/components/lib.tsx @@ -1,13 +1,7 @@ import { SetupContext } from 'vue'; -import { MenuSide, SvgIcon } from './base'; +import { MenuSide, SvgIcon, NavIcons } from './base'; -; - -export function NavHeader() { +export const NavHeader = () => { return (
@@ -24,6 +18,7 @@ export function NavHeader() {
Web-Rtc
+
@@ -32,20 +27,27 @@ export function NavHeader() {
); -} +}; -export function FullScreenBox( - props: { dire: 'col' | 'row' }, +export type FullHeightFlexBoxProps = Partial<{ + dire: 'col' | 'row'; + type: 'full' | 'screen'; +}>; + +export const FullHeightFlexBox = ( + props: FullHeightFlexBoxProps, ctx: SetupContext -) { - const { dire } = props; +) => { + const { dire = 'row', type = 'screen' } = props; + + const height: Record<'full' | 'screen', string> = { + full: 'h-full', + screen: 'h-screen', + }; + return ( -
+
{ctx.slots.default?.()}
); -} - -export function NavContent(_: unknown, ctx: SetupContext) { - return
{ctx.slots.default?.()}
; -} +}; diff --git a/client/packages/rtc-web/src/hooks/index.ts b/client/packages/rtc-web/src/hooks/index.ts new file mode 100644 index 0000000..7baad7d --- /dev/null +++ b/client/packages/rtc-web/src/hooks/index.ts @@ -0,0 +1 @@ +export * from './useTheme'; diff --git a/client/packages/rtc-web/src/hooks/useTheme.ts b/client/packages/rtc-web/src/hooks/useTheme.ts new file mode 100644 index 0000000..b645835 --- /dev/null +++ b/client/packages/rtc-web/src/hooks/useTheme.ts @@ -0,0 +1,42 @@ +import { themeChange } from 'theme-change'; +import { useLocalStorage, usePreferredDark } from '@vueuse/core'; +import { onMounted, watch } from 'vue'; + +export enum ThemeEnum { + DARK = 'dark', + LIGHT = 'light', +} + +export const useTheme = () => { + const isPreferredDark = usePreferredDark(); + + const themeInfo = useLocalStorage( + 'rtc-theme', + isPreferredDark ? ThemeEnum.DARK : ThemeEnum.LIGHT + ); + + const setTheme = (theme: ThemeEnum) => { + themeInfo.value = theme; + }; + + return { + themeInfo, + setTheme, + }; +}; + +export const useSwitchTheme = () => { + const { themeInfo, setTheme } = useTheme(); + + watch( + () => themeInfo.value, + (v) => { + document.documentElement.setAttribute('data-theme', v); + }, + { + immediate: true, + } + ); + + return { themeInfo, setTheme }; +}; diff --git a/client/packages/rtc-web/src/layout/index.vue b/client/packages/rtc-web/src/layout/index.vue index f3cab89..601db61 100644 --- a/client/packages/rtc-web/src/layout/index.vue +++ b/client/packages/rtc-web/src/layout/index.vue @@ -1,6 +1,6 @@ diff --git a/client/packages/rtc-web/src/main.ts b/client/packages/rtc-web/src/main.ts index 51f4b5e..f8ccbe9 100644 --- a/client/packages/rtc-web/src/main.ts +++ b/client/packages/rtc-web/src/main.ts @@ -1,12 +1,15 @@ import { createApp } from 'vue'; import './assets/styles/index.css'; -import App from './App.vue'; + +import router from './routes'; import 'virtual:svg-icons-register'; import SvgIcon from '@/components/base/svg-icon.vue'; +import App from './App.vue'; + function setup() { - return createApp(App).component('svg-icon', SvgIcon); + return createApp(App).use(router).component('svg-icon', SvgIcon); } setup().mount('#app'); diff --git a/client/packages/rtc-web/src/routes/index.ts b/client/packages/rtc-web/src/routes/index.ts new file mode 100644 index 0000000..3502572 --- /dev/null +++ b/client/packages/rtc-web/src/routes/index.ts @@ -0,0 +1,8 @@ +import { createWebHistory, createRouter } from 'vue-router'; + +import { routes } from './router'; + +export default createRouter({ + history: createWebHistory(), + routes, +}); diff --git a/client/packages/rtc-web/src/routes/router.ts b/client/packages/rtc-web/src/routes/router.ts new file mode 100644 index 0000000..b713658 --- /dev/null +++ b/client/packages/rtc-web/src/routes/router.ts @@ -0,0 +1,4 @@ +export const routes = [ + { path: '/', component: () => import('@/views/welcome.vue') }, + { path: '/chat', component: () => import('@/views/chat/chat.vue') }, +]; diff --git a/client/packages/rtc-web/src/views/chat/chat.vue b/client/packages/rtc-web/src/views/chat/chat.vue new file mode 100644 index 0000000..bdb53c7 --- /dev/null +++ b/client/packages/rtc-web/src/views/chat/chat.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/client/packages/rtc-web/src/views/file/file.vue b/client/packages/rtc-web/src/views/file/file.vue new file mode 100644 index 0000000..13d7b1e --- /dev/null +++ b/client/packages/rtc-web/src/views/file/file.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/client/packages/rtc-web/src/views/welcome.vue b/client/packages/rtc-web/src/views/welcome.vue new file mode 100644 index 0000000..184e808 --- /dev/null +++ b/client/packages/rtc-web/src/views/welcome.vue @@ -0,0 +1,11 @@ + + + + + diff --git a/client/packages/rtc-web/tailwind.config.js b/client/packages/rtc-web/tailwind.config.js index 1de13d1..61c865e 100644 --- a/client/packages/rtc-web/tailwind.config.js +++ b/client/packages/rtc-web/tailwind.config.js @@ -1,6 +1,10 @@ /** @type {import('tailwindcss').Config} */ export default { + darkMode: 'class', content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], + daisyui: { + themes: ['light', 'dark'], + }, theme: { extend: {}, }, diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml index d8a6fc9..4c605c7 100644 --- a/client/pnpm-lock.yaml +++ b/client/pnpm-lock.yaml @@ -12,6 +12,7 @@ importers: '@typescript-eslint/parser': ^5.60.0 '@vitejs/plugin-vue': ^4.2.3 '@vitejs/plugin-vue-jsx': ^3.0.1 + '@vueuse/core': ^10.2.0 autoprefixer: ^10.4.14 daisyui: ^3.1.6 eslint: ^8.43.0 @@ -23,16 +24,21 @@ importers: prettier: ^2.8.8 prettier-plugin-tailwindcss: ^0.3.0 tailwindcss: ^3.3.2 + theme-change: ^2.5.0 typescript: ^5.1.3 vite: ^4.3.9 vite-plugin-eslint: ^1.8.1 vite-plugin-svg-icons: ^2.0.1 vue: ^3.3.4 vue-eslint-parser: ^9.3.1 + vue-router: '4' vue-tsc: ^1.8.1 dependencies: '@vitejs/plugin-vue-jsx': 3.0.1_vite@4.3.9+vue@3.3.4 + '@vueuse/core': 10.2.0_vue@3.3.4 + theme-change: 2.5.0 vue: 3.3.4 + vue-router: 4.2.2_vue@3.3.4 devDependencies: '@types/node': 20.3.2 '@typescript-eslint/eslint-plugin': 5.60.1_emhilanx7rvvqwlixwztbx5x2m @@ -687,6 +693,10 @@ packages: '@types/node': 20.3.2 dev: true + /@types/web-bluetooth/0.0.17: + resolution: {integrity: sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA==} + dev: false + /@typescript-eslint/eslint-plugin/5.60.1_emhilanx7rvvqwlixwztbx5x2m: resolution: {integrity: sha512-KSWsVvsJsLJv3c4e73y/Bzt7OpqMCADUO846bHcuWYSYM19bldbAeDv7dYyV0jwkbMfJ2XdlzwjhXtuD7OY6bw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -919,6 +929,10 @@ packages: '@vue/compiler-dom': 3.3.4 '@vue/shared': 3.3.4 + /@vue/devtools-api/6.5.0: + resolution: {integrity: sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==} + dev: false + /@vue/language-core/1.8.2_typescript@5.1.3: resolution: {integrity: sha512-QJujhmp89TRoWwzjn2sPMezG97+mNyaCTfznGHWNCE3LBsillZCBqAO7M7cxO8ee1V3r+qHjWytkoh3M4YkRJw==} peerDependencies: @@ -986,6 +1000,31 @@ packages: - typescript dev: true + /@vueuse/core/10.2.0_vue@3.3.4: + resolution: {integrity: sha512-aHBnoCteIS3hFu7ZZkVB93SanVDY6t4TIb7XDLxJT/HQdAZz+2RdIEJ8rj5LUoEJr7Damb5+sJmtpCwGez5ozQ==} + dependencies: + '@types/web-bluetooth': 0.0.17 + '@vueuse/metadata': 10.2.0 + '@vueuse/shared': 10.2.0_vue@3.3.4 + vue-demi: 0.14.5_vue@3.3.4 + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + + /@vueuse/metadata/10.2.0: + resolution: {integrity: sha512-IR7Mkq6QSgZ38q/2ZzOt+Zz1OpcEsnwE64WBumDQ+RGKrosFCtUA2zgRrOqDEzPBXrVB+4HhFkwDjQMu0fDBKw==} + dev: false + + /@vueuse/shared/10.2.0_vue@3.3.4: + resolution: {integrity: sha512-dIeA8+g9Av3H5iF4NXR/sft4V6vys76CpZ6hxwj8eMXybXk2WRl3scSsOVi+kQ9SX38COR7AH7WwY83UcuxbSg==} + dependencies: + vue-demi: 0.14.5_vue@3.3.4 + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + /acorn-jsx/5.3.2_acorn@8.9.0: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -3283,6 +3322,10 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /theme-change/2.5.0: + resolution: {integrity: sha512-B/UdsgdHAGhSKHTAQnxg/etN0RaMDpehuJmZIjLMDVJ6DGIliRHGD6pODi1CXLQAN9GV0GSyB3G6yCuK05PkPQ==} + dev: false + /thenify-all/1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -3493,6 +3536,21 @@ packages: optionalDependencies: fsevents: 2.3.2 + /vue-demi/0.14.5_vue@3.3.4: + resolution: {integrity: sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + dependencies: + vue: 3.3.4 + dev: false + /vue-eslint-parser/9.3.1_eslint@8.43.0: resolution: {integrity: sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==} engines: {node: ^14.17.0 || >=16.0.0} @@ -3511,6 +3569,15 @@ packages: - supports-color dev: true + /vue-router/4.2.2_vue@3.3.4: + resolution: {integrity: sha512-cChBPPmAflgBGmy3tBsjeoe3f3VOSG6naKyY5pjtrqLGbNEXdzCigFUHgBvp9e3ysAtFtEx7OLqcSDh/1Cq2TQ==} + peerDependencies: + vue: ^3.2.0 + dependencies: + '@vue/devtools-api': 6.5.0 + vue: 3.3.4 + dev: false + /vue-template-compiler/2.7.14: resolution: {integrity: sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==} dependencies: