🎉 Initial template frontend setup #1

Merged
torge-hmn merged 2 commits from frontend-setup into main 2024-11-17 16:47:13 +00:00
23 changed files with 3144 additions and 0 deletions

4
frontend/.browserslistrc Normal file
View file

@ -0,0 +1,4 @@
> 1%
last 2 versions
not dead
not ie 11

6
frontend/.editorconfig Normal file
View file

@ -0,0 +1,6 @@
[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}]
charset = utf-8
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

22
frontend/.gitignore vendored Normal file
View file

@ -0,0 +1,22 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

15
frontend/components.d.ts vendored Normal file
View file

@ -0,0 +1,15 @@
/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
Home: typeof import('./src/components/Home.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}
}

2
frontend/env.d.ts vendored Normal file
View file

@ -0,0 +1,2 @@
/// <reference types="vite/client" />
/// <reference types="unplugin-vue-router/client" />

30
frontend/eslint.config.js Normal file
View file

@ -0,0 +1,30 @@
import pluginVue from 'eslint-plugin-vue'
import vueTsEslintConfig from '@vue/eslint-config-typescript'
export default [
{
name: 'app/files-to-lint',
files: ['**/*.{ts,mts,tsx,vue}'],
},
{
name: 'app/files-to-ignore',
ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'],
},
...pluginVue.configs['flat/recommended'],
...vueTsEslintConfig(),
{
rules: {
'@typescript-eslint/no-unused-expressions': [
'error',
{
allowShortCircuit: true,
allowTernary: true,
},
],
'vue/multi-word-component-names': 'off',
}
}
]

13
frontend/index.html Normal file
View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>home-cert-manager</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

42
frontend/package.json Normal file
View file

@ -0,0 +1,42 @@
{
"name": "frontend",
"private": true,
"type": "module",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build --force",
"lint": "eslint . --fix"
},
"dependencies": {
"@mdi/font": "7.4.47",
"core-js": "^3.37.1",
"roboto-fontface": "*",
"vue": "^3.4.31",
"vuetify": "^3.6.14"
},
"devDependencies": {
"@eslint/js": "^9.14.0",
"@tsconfig/node22": "^22.0.0",
"@types/node": "^22.9.0",
"@vitejs/plugin-vue": "^5.1.4",
"@vue/eslint-config-typescript": "^14.1.3",
"@vue/tsconfig": "^0.5.1",
"eslint": "^9.14.0",
"eslint-plugin-vue": "^9.30.0",
"npm-run-all2": "^7.0.1",
"sass": "1.77.8",
"sass-embedded": "^1.77.8",
"typescript": "~5.6.3",
"unplugin-fonts": "^1.1.1",
"unplugin-vue-components": "^0.27.2",
"unplugin-vue-router": "^0.10.0",
"vite": "^5.4.10",
"vite-plugin-vuetify": "^2.0.3",
"vue-router": "^4.4.0",
"vue-tsc": "^2.1.10"
}
}

2715
frontend/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load diff

BIN
frontend/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

11
frontend/src/App.vue Normal file
View file

@ -0,0 +1,11 @@
<template>
<v-app>
<v-main>
<router-view />
</v-main>
</v-app>
</template>
<script lang="ts" setup>
//
</script>

View file

@ -0,0 +1,84 @@
<template>
<v-container class="fill-height">
<v-responsive
class="align-centerfill-height mx-auto"
max-width="900"
>
<div class="text-center">
<div class="text-body-2 font-weight-light mb-n1">Welcome to</div>
<h1 class="text-h2 font-weight-bold">home-cert-manager</h1>
</div>
<div class="py-4" />
<v-row>
<v-col cols="12">
<v-card
class="py-4"
color="surface-variant"
image="https://cdn.vuetifyjs.com/docs/images/one/create/feature.png"
prepend-icon="mdi-rocket-launch-outline"
rounded="lg"
variant="outlined"
>
<template #image>
<v-img position="top right" />
</template>
<template #title>
<h2 class="text-h5 font-weight-bold">Get started</h2>
</template>
</v-card>
</v-col>
<v-col cols="6">
<v-card
class="py-4"
color="surface-variant"
prepend-icon="mdi-certificate"
rounded="lg"
title="Manage your certificates"
variant="text"
/>
</v-col>
<v-col cols="6">
<v-card
class="py-4"
color="surface-variant"
prepend-icon="mdi-home-lock"
rounded="lg"
title="Secure your home lab"
variant="text"
/>
</v-col>
<v-col cols="6">
<v-card
class="py-4"
color="surface-variant"
prepend-icon="mdi-domain"
rounded="lg"
title="Domain management"
variant="text"
/>
</v-col>
<v-col cols="6">
<v-card
class="py-4"
color="surface-variant"
prepend-icon="mdi-web"
rounded="lg"
title="Internet certificate support"
variant="text"
/>
</v-col>
</v-row>
</v-responsive>
</v-container>
</template>
<script setup lang="ts">
//
</script>

11
frontend/src/main.ts Normal file
View file

@ -0,0 +1,11 @@
import { registerPlugins } from '@/plugins'
import App from './App.vue'
import { createApp } from 'vue'
const app = createApp(App)
registerPlugins(app)
app.mount('#app')

View file

@ -0,0 +1,7 @@
<template>
<Home />
</template>
<script lang="ts" setup>
import Home from "@/components/Home.vue";
</script>

View file

@ -0,0 +1,10 @@
import vuetify from './vuetify'
import router from '../router'
import type { App } from 'vue'
export function registerPlugins (app: App) {
app
.use(vuetify)
.use(router)
}

View file

@ -0,0 +1,10 @@
import '@mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
import { createVuetify } from 'vuetify'
export default createVuetify({
theme: {
defaultTheme: 'dark',
},
})

View file

@ -0,0 +1,28 @@
import { createRouter, createWebHistory } from 'vue-router/auto'
import { routes } from 'vue-router/auto-routes'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
})
// Workaround for https://github.com/vitejs/vite/issues/11804
router.onError((err, to) => {
if (err?.message?.includes?.('Failed to fetch dynamically imported module')) {
if (!localStorage.getItem('vuetify:dynamic-reload')) {
console.log('Reloading page to fix dynamic import error')
localStorage.setItem('vuetify:dynamic-reload', 'true')
location.assign(to.fullPath)
} else {
console.error('Dynamic import error, reloading page did not fix it', err)
}
} else {
console.error(err)
}
})
router.isReady().then(() => {
localStorage.removeItem('vuetify:dynamic-reload')
})
export default router

View file

@ -0,0 +1,10 @@
/**
* src/styles/settings.scss
*
* Configures SASS variables and Vuetify overwrites
*/
// https://vuetifyjs.com/features/sass-variables/`
// @use 'vuetify/settings' with (
// $color-pack: false
// );

View file

@ -0,0 +1,14 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}

11
frontend/tsconfig.json Normal file
View file

@ -0,0 +1,11 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}

View file

@ -0,0 +1,19 @@
{
"extends": "@tsconfig/node22/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*"
],
"compilerOptions": {
"composite": true,
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}

23
frontend/typed-router.d.ts vendored Normal file
View file

@ -0,0 +1,23 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-router. ‼️ DO NOT MODIFY THIS FILE ‼️
// It's recommended to commit this file.
// Make sure to add this file to your tsconfig.json file as an "includes" or "files" entry.
declare module 'vue-router/auto-routes' {
import type {
RouteRecordInfo,
ParamValue,
ParamValueOneOrMore,
ParamValueZeroOrMore,
ParamValueZeroOrOne,
} from 'vue-router'
/**
* Route name map generated by unplugin-vue-router
*/
export interface RouteNamedMap {
'/': RouteRecordInfo<'/', '/', Record<never, never>, Record<never, never>>,
}
}

57
frontend/vite.config.mts Normal file
View file

@ -0,0 +1,57 @@
import Components from 'unplugin-vue-components/vite'
import Vue from '@vitejs/plugin-vue'
import Vuetify, { transformAssetUrls } from 'vite-plugin-vuetify'
import ViteFonts from 'unplugin-fonts/vite'
import VueRouter from 'unplugin-vue-router/vite'
import { defineConfig } from 'vite'
import { fileURLToPath, URL } from 'node:url'
export default defineConfig({
plugins: [
VueRouter(),
Vue({
template: { transformAssetUrls },
}),
Vuetify({
autoImport: true,
styles: {
configFile: 'src/styles/settings.scss',
},
}),
Components(),
ViteFonts({
google: {
families: [ {
name: 'Roboto',
styles: 'wght@100;300;400;500;700;900',
}],
},
}),
],
define: { 'process.env': {} },
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
extensions: [
'.js',
'.json',
'.jsx',
'.mjs',
'.ts',
'.tsx',
'.vue',
],
},
server: {
port: 3000,
},
css: {
preprocessorOptions: {
sass: {
api: 'modern-compiler',
},
},
},
})