First commit
This commit is contained in:
Executable
+24
@@ -0,0 +1,24 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar"]
|
||||
}
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
# Nocos Frontend
|
||||
Vue 3.5 + Vue Router 5.0 + Vite 7.2
|
||||
Executable
+77
@@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>LynqChat</title>
|
||||
<link rel="icon" href="/lynqchat.svg" type="image/svg+xml">
|
||||
</head>
|
||||
<body>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html, body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
font-size: 16px;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html, body {
|
||||
background-color: #1b1b1b;
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
position: fixed;
|
||||
inset: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 6rem;
|
||||
height: 6rem;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
.progress {
|
||||
border: 0.4rem solid #425C97;
|
||||
border-radius: 100%;
|
||||
border-top: 0.4rem solid #ffffff;
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="loading">
|
||||
<img
|
||||
class="logo"
|
||||
src="/lynqchat.svg"
|
||||
/>
|
||||
|
||||
<div class="progress" />
|
||||
</div>
|
||||
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"license": "AGPL-3.0-only",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc -b && vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"dexie": "^4.3.0",
|
||||
"vue": "^3.5.24",
|
||||
"vue-router": "^5.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.10.1",
|
||||
"@vitejs/plugin-vue": "^6.0.1",
|
||||
"@vue/tsconfig": "^0.8.1",
|
||||
"typescript": "~5.9.3",
|
||||
"vite": "^8.0.0",
|
||||
"vue-tsc": "^3.1.4"
|
||||
},
|
||||
"packageManager": "pnpm@10.29.1"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<svg width="4096" height="4096" viewBox="0 0 4096 4096" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="4096" height="4096" fill="#1E1E1E"/>
|
||||
<rect width="4096" height="4096" fill="#425C97"/>
|
||||
<rect x="546" y="1086" width="155.544" height="1011.04" rx="77.7722" fill="white"/>
|
||||
<rect x="1168.18" y="1941.49" width="155.544" height="622.177" rx="77.7722" transform="rotate(90 1168.18 1941.49)" fill="white"/>
|
||||
<path d="M1674.03 1913.56C1691.75 1951.65 1679.85 1996.96 1645.71 2021.43C1601.21 2053.32 1538.68 2036.9 1515.59 1987.26L1325.79 1579.23C1298.84 1521.31 1341.13 1455 1405.01 1455C1438.99 1455 1469.9 1474.71 1484.23 1505.52L1674.03 1913.56Z" fill="white"/>
|
||||
<path d="M1520.23 2377.11C1505.89 2407.93 1474.99 2427.64 1441 2427.64C1377.13 2427.64 1334.84 2361.33 1361.78 2303.41L1732.93 1505.52C1747.26 1474.71 1778.16 1455 1812.15 1455C1876.03 1455 1918.32 1521.31 1891.37 1579.23L1520.23 2377.11Z" fill="white"/>
|
||||
<path d="M2849 1439C2959.46 1439 3049 1528.54 3049 1639V2021.23C3049 2064.18 3014.18 2099 2971.23 2099C2928.28 2099 2893.46 2064.18 2893.46 2021.23V1639C2893.46 1614.83 2874.17 1595.16 2850.15 1594.55L2849 1594.54H2249L2247.85 1594.55C2223.83 1595.16 2204.54 1614.83 2204.54 1639V2021.23C2204.54 2064.18 2169.72 2099 2126.77 2099C2083.82 2099 2049 2064.18 2049 2021.23V1639C2049 1528.54 2138.54 1439 2249 1439H2849Z" fill="white"/>
|
||||
<path d="M2749 1766.77H3389C3434.41 1766.77 3471.23 1803.59 3471.23 1849V2149C3471.23 2216.51 3416.51 2271.23 3349 2271.23H2749C2681.49 2271.23 2626.77 2216.51 2626.77 2149V1889C2626.77 1821.49 2681.49 1766.77 2749 1766.77Z" stroke="white" stroke-width="155.54"/>
|
||||
<path d="M3393.46 1689C3479.62 1689 3549.46 1758.84 3549.46 1845V2931C3549.46 2974.08 3514.54 3009 3471.46 3009C3428.38 3009 3393.46 2974.08 3393.46 2931V1689Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
Executable
+27
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<Progress
|
||||
v-show="routerStatus.isLoad"
|
||||
class="router-progress"
|
||||
:size="6"
|
||||
/>
|
||||
|
||||
<main>
|
||||
<RouterView
|
||||
:key="$route.fullPath"
|
||||
/>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.router-progress {
|
||||
position: fixed;
|
||||
inset: 0.5rem 0.5rem 0 auto;
|
||||
z-index: 9999;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { RouterView } from "vue-router";
|
||||
import routerStatus from "@/lib/router";
|
||||
import Progress from "@/components/Progress.vue";
|
||||
</script>
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div class="progress" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.progress {
|
||||
border: v-bind(borderSize) solid #425C97;
|
||||
border-radius: 100%;
|
||||
border-top: v-bind(borderSize) solid #ffffff;
|
||||
width: v-bind(size);
|
||||
height: v-bind(size);
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const props = defineProps<{
|
||||
size: number;
|
||||
}>();
|
||||
|
||||
const size = `${props.size * 0.25}rem`;
|
||||
const borderSize = `${props.size / 3}px`;
|
||||
</script>
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
:root {
|
||||
--bg-color: #ffffff;
|
||||
--text-color: #000000;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bg-color: #1b1b1b;
|
||||
--text-color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html, body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
font-size: 16px;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import Dexie, { type EntityTable } from "dexie";
|
||||
|
||||
export interface Settings {
|
||||
id: number;
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface Server {
|
||||
id: number;
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export default class extends Dexie {
|
||||
server!: EntityTable<Server, "id">;
|
||||
settings!: EntityTable<Settings, "id">;
|
||||
|
||||
constructor() {
|
||||
super("lynq-chat");
|
||||
|
||||
this.version(1).stores({
|
||||
server: "++id,&name",
|
||||
settings: "++id,&name",
|
||||
});
|
||||
|
||||
/*(async () => {
|
||||
await this.open();
|
||||
|
||||
await this.transaction("rw", this.settings, async () => {
|
||||
const defaults = {
|
||||
"key": "value",
|
||||
};
|
||||
|
||||
for (const [name, value] of Object.entries(defaults)) {
|
||||
const exists = await this.settings
|
||||
.where("name")
|
||||
.equals(name)
|
||||
.first();
|
||||
|
||||
if (!exists) {
|
||||
await this.settings.add({ name, value });
|
||||
}
|
||||
}
|
||||
});
|
||||
})();*/
|
||||
};
|
||||
}
|
||||
|
||||
export async function getByIndex<T>(
|
||||
table: EntityTable<T, any>,
|
||||
index: string,
|
||||
indexValue: any
|
||||
): Promise<T | undefined> {
|
||||
return await table.where(index).equals(indexValue).first();
|
||||
}
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
import { reactive } from "vue";
|
||||
|
||||
const routerStatus = reactive<{
|
||||
isLoad: boolean;
|
||||
}>({
|
||||
isLoad: false,
|
||||
});
|
||||
|
||||
export default routerStatus;
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
import { createApp } from "vue";
|
||||
import { createRouter, createWebHistory } from "vue-router";
|
||||
import routerStatus from "@/lib/router";
|
||||
|
||||
import "@/global.css";
|
||||
import Layout from "@/Layout.vue";
|
||||
|
||||
const app = createApp(Layout);
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
routes: [
|
||||
{
|
||||
path: "/",
|
||||
component: () => import("@/routes/index.vue"),
|
||||
},
|
||||
],
|
||||
});
|
||||
// @ts-ignore 余分な引数の警告
|
||||
router.beforeEach((to, from, next) => {
|
||||
routerStatus.isLoad = true;
|
||||
next();
|
||||
});
|
||||
router.afterEach(() => {
|
||||
routerStatus.isLoad = false;
|
||||
});
|
||||
app.use(router);
|
||||
|
||||
app.mount("body");
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
<template>
|
||||
<h1>Hello World</h1>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
</script>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
export {}
|
||||
|
||||
declare global {
|
||||
}
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"types": ["vite/client"],
|
||||
"typeRoots": ["./node_modules/"],
|
||||
"target": "ES2023",
|
||||
"lib": ["ES2023", "DOM"],
|
||||
"module": "ESNext",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true,
|
||||
|
||||
/* Alias */
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
},
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.ts",
|
||||
"./src/**/*.tsx",
|
||||
"./src/**/*.vue",
|
||||
],
|
||||
}
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
},
|
||||
},
|
||||
}
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2023",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"types": ["node"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
import { defineConfig, loadEnv } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import path from "path";
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd(), "")
|
||||
const apiPort = Number(env.VITE_API_PORT) || 3300
|
||||
|
||||
return {
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
hmr: {
|
||||
clientPort: 5173,
|
||||
protocol: "ws",
|
||||
},
|
||||
proxy: {
|
||||
"/api": {
|
||||
target: `http://localhost:${apiPort}`,
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": path.resolve(__dirname, "src"),
|
||||
},
|
||||
},
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user