commit
5d57b4ae12
@ -0,0 +1,15 @@
|
||||
/* eslint-env node */
|
||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
'extends': [
|
||||
'plugin:vue/vue3-essential',
|
||||
'eslint:recommended',
|
||||
'@vue/eslint-config-typescript',
|
||||
'@vue/eslint-config-prettier/skip-formatting'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest'
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/prettierrc",
|
||||
"semi": false,
|
||||
"tabWidth": 2,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none"
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"Vue.volar",
|
||||
"Vue.vscode-typescript-vue-plugin",
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
# auth-ui
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
|
||||
|
||||
## Type Support for `.vue` Imports in TS
|
||||
|
||||
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
|
||||
|
||||
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
|
||||
|
||||
1. Disable the built-in TypeScript Extension
|
||||
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
|
||||
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
|
||||
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Type-Check, Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lint with [ESLint](https://eslint.org/)
|
||||
|
||||
```sh
|
||||
npm run lint
|
||||
```
|
||||
@ -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>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "auth-ui",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check \"build-only {@}\" --",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
||||
"format": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.3.4",
|
||||
"vue-router": "^4.2.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.3.3",
|
||||
"@tsconfig/node18": "^18.2.2",
|
||||
"@types/node": "^18.18.5",
|
||||
"@vitejs/plugin-vue": "^4.4.0",
|
||||
"@vue/eslint-config-prettier": "^8.0.0",
|
||||
"@vue/eslint-config-typescript": "^12.0.0",
|
||||
"@vue/tsconfig": "^0.4.0",
|
||||
"eslint": "^8.49.0",
|
||||
"eslint-plugin-vue": "^9.17.0",
|
||||
"npm-run-all2": "^6.1.1",
|
||||
"prettier": "^3.0.3",
|
||||
"typescript": "~5.2.0",
|
||||
"vite": "^4.4.11",
|
||||
"vue-tsc": "^1.8.19"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { RouterView } from 'vue-router'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<RouterView />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
@ -0,0 +1,82 @@
|
||||
/* fonts */
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Mulish:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&family=Roboto:wght@400;500&display=swap');
|
||||
|
||||
/* color palette from <https://github.com/vuejs/theme> */
|
||||
:root {
|
||||
--vt-c-white: #ffffff;
|
||||
--vt-c-white-soft: #f8f8f8;
|
||||
--vt-c-white-mute: #f2f2f2;
|
||||
|
||||
--vt-c-black: #181818;
|
||||
--vt-c-black-soft: #222222;
|
||||
--vt-c-black-mute: #282828;
|
||||
|
||||
--vt-c-indigo: #2c3e50;
|
||||
|
||||
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
||||
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
||||
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
||||
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
||||
|
||||
--vt-c-text-light-1: var(--vt-c-indigo);
|
||||
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
||||
--vt-c-text-dark-1: var(--vt-c-white);
|
||||
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
||||
}
|
||||
|
||||
:root {
|
||||
--purple-soft: #EAE9F0;
|
||||
--white-soft: #FBFBFB;
|
||||
--purple: #1B0554;
|
||||
--purple-light: #321e65;
|
||||
--text-dark: #383445;
|
||||
--text-body: #5E5673;
|
||||
--text-body-light: #736C88;
|
||||
--grey: #6E6781;
|
||||
--grey-light: #C1BEC7;
|
||||
--red: #F41F4E;
|
||||
--yellow: #FFD43E;
|
||||
--green: #40CE4E;
|
||||
}
|
||||
|
||||
/* semantic color variables for this project */
|
||||
:root {
|
||||
--color-background: var(--purple-soft);
|
||||
|
||||
--color-border: var(--vt-c-divider-light-2);
|
||||
--color-border-hover: var(--vt-c-divider-light-1);
|
||||
|
||||
--color-heading: var(--text-dark);
|
||||
--color-text: var(--text-body);
|
||||
|
||||
--color-drop-shadow: #d9d4e3;
|
||||
|
||||
--section-gap: 160px;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
color: var(--color-text);
|
||||
background: var(--color-background);
|
||||
transition:
|
||||
color 0.5s,
|
||||
background-color 0.5s;
|
||||
line-height: 1.6;
|
||||
font-family:
|
||||
'Mulish',
|
||||
Inter,
|
||||
sans-serif;
|
||||
font-size: 15px;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@ -0,0 +1,35 @@
|
||||
@import './base.css';
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
font-weight: normal;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
input {
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
font-family: 'Mulish';
|
||||
margin-bottom: 0.8em;
|
||||
padding: 1em;
|
||||
border: 2px solid var(--text-body-light);
|
||||
border-radius: 5px;
|
||||
color: var(--text-body);
|
||||
background-color: var(--white-soft);
|
||||
}
|
||||
button {
|
||||
font-family: 'Mulish';
|
||||
border: none;
|
||||
background-color: var(--purple);
|
||||
color: var(--white-soft);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
border-radius: 5px;
|
||||
padding: 1em;
|
||||
}
|
||||
button:hover {
|
||||
background-color: var(--purple-light);
|
||||
cursor: pointer;
|
||||
}
|
||||
@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div class="soc-wrapper">
|
||||
<button class="gsi-material-button">
|
||||
<div class="gsi-material-button-state"></div>
|
||||
<div class="gsi-material-button-content-wrapper">
|
||||
<div class="gsi-material-button-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" class="mr-2" viewBox="0 0 1792 1792">
|
||||
<path d="M896 128q209 0 385.5 103t279.5 279.5 103 385.5q0 251-146.5 451.5t-378.5 277.5q-27 5-40-7t-13-30q0-3 .5-76.5t.5-134.5q0-97-52-142 57-6 102.5-18t94-39 81-66.5 53-105 20.5-150.5q0-119-79-206 37-91-8-204-28-9-81 11t-92 44l-38 24q-93-26-192-26t-192 26q-16-11-42.5-27t-83.5-38.5-85-13.5q-45 113-8 204-79 87-79 206 0 85 20.5 150t52.5 105 80.5 67 94 39 102.5 18q-39 36-49 103-21 10-45 15t-57 5-65.5-21.5-55.5-62.5q-19-32-48.5-52t-49.5-24l-20-3q-21 0-29 4.5t-5 11.5 9 14 13 12l7 5q22 10 43.5 38t31.5 51l10 23q13 38 44 61.5t67 30 69.5 7 55.5-3.5l23-4q0 38 .5 88.5t.5 54.5q0 18-13 30t-40 7q-232-77-378.5-277.5t-146.5-451.5q0-209 103-385.5t279.5-279.5 385.5-103zm-477 1103q3-7-7-12-10-3-13 2-3 7 7 12 9 6 13-2zm31 34q7-5-2-16-10-9-16-3-7 5 2 16 10 10 16 3zm30 45q9-7 0-19-8-13-17-6-9 5 0 18t17 7zm42 42q8-8-4-19-12-12-20-3-9 8 4 19 12 12 20 3zm57 25q3-11-13-16-15-4-19 7t13 15q15 6 19-6zm63 5q0-13-17-11-16 0-16 11 0 13 17 11 16 0 16-11zm58-10q-2-11-18-9-16 3-14 15t18 8 14-14z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="gsi-material-button-contents">Sign in with GitHub</span>
|
||||
<span style="display: none;">Sign in with GitHub</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.soc-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.gsi-material-button {
|
||||
display: block;
|
||||
margin: 0px auto;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-appearance: none;
|
||||
background-color: WHITE;
|
||||
background-image: none;
|
||||
border: 1px solid var(--grey-light);
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
color: #1f1f1f;
|
||||
cursor: pointer;
|
||||
font-family: 'Roboto', arial, sans-serif;
|
||||
font-size: 14px;
|
||||
height: 46px;
|
||||
letter-spacing: 0.25px;
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
padding: 0 12px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
-webkit-transition: background-color .218s, border-color .218s, box-shadow .218s;
|
||||
transition: background-color .218s, border-color .218s, box-shadow .218s;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
width: auto;
|
||||
width: 240px;
|
||||
min-width: min-content;
|
||||
}
|
||||
|
||||
.gsi-material-button .gsi-material-button-icon {
|
||||
height: 20px;
|
||||
margin-right: 12px;
|
||||
min-width: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.gsi-material-button .gsi-material-button-content-wrapper {
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-flex-wrap: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
height: 100%;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.gsi-material-button .gsi-material-button-contents {
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
font-family: 'Roboto', arial, sans-serif;
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.gsi-material-button .gsi-material-button-state {
|
||||
-webkit-transition: opacity .218s;
|
||||
transition: opacity .218s;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.gsi-material-button:disabled {
|
||||
cursor: default;
|
||||
background-color: #ffffff61;
|
||||
border-color: #1f1f1f1f;
|
||||
}
|
||||
|
||||
.gsi-material-button:disabled .gsi-material-button-contents {
|
||||
opacity: 38%;
|
||||
}
|
||||
|
||||
.gsi-material-button:disabled .gsi-material-button-icon {
|
||||
opacity: 38%;
|
||||
}
|
||||
|
||||
.gsi-material-button:not(:disabled):active .gsi-material-button-state,
|
||||
.gsi-material-button:not(:disabled):focus .gsi-material-button-state {
|
||||
background-color: #303030;
|
||||
opacity: 12%;
|
||||
}
|
||||
.gsi-material-button:not(:disabled):hover .gsi-material-button-state {
|
||||
background-color: #303030;
|
||||
opacity: 8%;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<div class="soc-wrapper">
|
||||
<button class="gsi-material-button">
|
||||
<div class="gsi-material-button-state"></div>
|
||||
<div class="gsi-material-button-content-wrapper">
|
||||
<div class="gsi-material-button-icon">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" xmlns:xlink="http://www.w3.org/1999/xlink" style="display: block;">
|
||||
<path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"></path>
|
||||
<path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"></path>
|
||||
<path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"></path>
|
||||
<path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"></path>
|
||||
<path fill="none" d="M0 0h48v48H0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="gsi-material-button-contents">Sign in with Google</span>
|
||||
<span style="display: none;">Sign in with Google</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.soc-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.gsi-material-button {
|
||||
display: block;
|
||||
margin: 0px auto;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-appearance: none;
|
||||
background-color: WHITE;
|
||||
background-image: none;
|
||||
border: 1px solid var(--grey-light);
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
color: #1f1f1f;
|
||||
cursor: pointer;
|
||||
font-family: 'Roboto', arial, sans-serif;
|
||||
font-size: 14px;
|
||||
height: 46px;
|
||||
letter-spacing: 0.25px;
|
||||
outline: none;
|
||||
overflow: hidden;
|
||||
padding: 0 12px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
-webkit-transition: background-color .218s, border-color .218s, box-shadow .218s;
|
||||
transition: background-color .218s, border-color .218s, box-shadow .218s;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
width: auto;
|
||||
width: 240px;
|
||||
min-width: min-content;
|
||||
}
|
||||
|
||||
.gsi-material-button .gsi-material-button-icon {
|
||||
height: 20px;
|
||||
margin-right: 12px;
|
||||
min-width: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.gsi-material-button .gsi-material-button-content-wrapper {
|
||||
-webkit-align-items: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-flex-wrap: nowrap;
|
||||
flex-wrap: nowrap;
|
||||
height: 100%;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.gsi-material-button .gsi-material-button-contents {
|
||||
-webkit-flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
font-family: 'Roboto', arial, sans-serif;
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.gsi-material-button .gsi-material-button-state {
|
||||
-webkit-transition: opacity .218s;
|
||||
transition: opacity .218s;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.gsi-material-button:disabled {
|
||||
cursor: default;
|
||||
background-color: #ffffff61;
|
||||
border-color: #1f1f1f1f;
|
||||
}
|
||||
|
||||
.gsi-material-button:disabled .gsi-material-button-contents {
|
||||
opacity: 38%;
|
||||
}
|
||||
|
||||
.gsi-material-button:disabled .gsi-material-button-icon {
|
||||
opacity: 38%;
|
||||
}
|
||||
|
||||
.gsi-material-button:not(:disabled):active .gsi-material-button-state,
|
||||
.gsi-material-button:not(:disabled):focus .gsi-material-button-state {
|
||||
background-color: #303030;
|
||||
opacity: 12%;
|
||||
}
|
||||
.gsi-material-button:not(:disabled):hover .gsi-material-button-state {
|
||||
background-color: #303030;
|
||||
opacity: 8%;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -0,0 +1,11 @@
|
||||
import './assets/main.css'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(router)
|
||||
|
||||
app.mount('#app')
|
||||
@ -0,0 +1,25 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import LoginView from "../views/LoginView.vue"
|
||||
import RegisterView from "../views/RegisterView.vue"
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
redirect: { path: '/register' },
|
||||
},
|
||||
{
|
||||
path: '/register',
|
||||
name: 'register',
|
||||
component: RegisterView,
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: LoginView,
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
export default router
|
||||
@ -0,0 +1,155 @@
|
||||
<script setup lang="ts">
|
||||
import GoogleLogin from '../components/GoogleLogin.vue'
|
||||
import GitHubLogin from '../components/GitHubLogin.vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="wrapper">
|
||||
<div class="container">
|
||||
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="160"/>
|
||||
<div class="login">
|
||||
<div class="socials">
|
||||
<GoogleLogin />
|
||||
<GitHubLogin />
|
||||
</div>
|
||||
<p class="separat-or"><span>or</span></p>
|
||||
<input type="email" name="tlg_email" id="tlg_email" placeholder="Email address">
|
||||
<input type="password" name="tlg_password" id="tlg_password" placeholder="Password">
|
||||
<button type="submit">Sign In</button>
|
||||
<div class="remember">
|
||||
<label for="tlg_remember" class="chk-container">Remember me for 30 days
|
||||
<input type="checkbox" name="tlg_remember" id="tlg_remember">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="view-switch">Don't have an account? <RouterLink class="rlink" to="/register">Create an account.</RouterLink></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.view-switch {
|
||||
text-align: center;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.rlink {
|
||||
text-decoration: none;
|
||||
color: var(--purple);
|
||||
font-weight: 700;
|
||||
}
|
||||
.rlink:hover {
|
||||
color: var(--purple-light);
|
||||
}
|
||||
.logo {
|
||||
display: block;
|
||||
margin: 1em auto 0em auto;
|
||||
}
|
||||
.container {
|
||||
padding: 2em 4em;
|
||||
background-color: var(--white-soft);
|
||||
border-radius: 5px;
|
||||
max-width: 440px;
|
||||
filter: drop-shadow(3px 6px 6px var(--color-drop-shadow));
|
||||
margin: auto;
|
||||
margin-top: 6vh;
|
||||
}
|
||||
.login {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.socials {
|
||||
margin: 3em 0em;
|
||||
}
|
||||
.socials > * {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
.separat-or {
|
||||
background-color: var(--white-soft);
|
||||
text-align: center;
|
||||
margin: 0px auto;
|
||||
margin-bottom: 3em;
|
||||
width: 90%;
|
||||
line-height: 0.1em;
|
||||
border-bottom: 2px solid var(--grey-light);
|
||||
}
|
||||
.separat-or span {
|
||||
background: var(--white-soft);
|
||||
padding:0 10px;
|
||||
}
|
||||
.remember {
|
||||
margin: 1em;
|
||||
margin-bottom: 2em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* custom checkmark code from https://www.w3schools.com/howto/howto_css_custom_checkbox.asp */
|
||||
|
||||
/* Customize the label (the container) */
|
||||
.chk-container {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding-left: 25px;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Hide the browser's default checkbox */
|
||||
.chk-container input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
height: 0;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
/* Create a custom checkbox */
|
||||
.checkmark {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 0;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
border-radius: 3px;
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
/* On mouse-over, add a grey background color */
|
||||
.chk-container:hover input ~ .checkmark {
|
||||
background-color: #bbb;
|
||||
}
|
||||
|
||||
/* When the checkbox is checked, add a blue background */
|
||||
.chk-container input:checked ~ .checkmark {
|
||||
background-color: var(--purple);
|
||||
}
|
||||
|
||||
/* Create the checkmark/indicator (hidden when not checked) */
|
||||
.checkmark:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Show the checkmark when checked */
|
||||
.chk-container input:checked ~ .checkmark:after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Style the checkmark/indicator */
|
||||
.chk-container .checkmark:after {
|
||||
left: 7px;
|
||||
top: 3px;
|
||||
width: 5px;
|
||||
height: 10px;
|
||||
border: solid white;
|
||||
border-width: 0 2px 2px 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,156 @@
|
||||
<script setup lang="ts">
|
||||
import GoogleLogin from '../components/GoogleLogin.vue'
|
||||
import GitHubLogin from '../components/GitHubLogin.vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="wrapper">
|
||||
<div class="container">
|
||||
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="160"/>
|
||||
<div class="login">
|
||||
<div class="socials">
|
||||
<GoogleLogin />
|
||||
<GitHubLogin />
|
||||
</div>
|
||||
<p class="separat-or"><span>or</span></p>
|
||||
<input type="email" name="tlg_email" id="tlg_email" placeholder="Email address">
|
||||
<input type="password" name="tlg_password" id="tlg_password" placeholder="Password">
|
||||
<input type="password" name="tlg_password_conf" id="tlg_password_conf" placeholder="Confirm password">
|
||||
<button type="submit">Sign In</button>
|
||||
<div class="remember">
|
||||
<label for="tlg_remember" class="chk-container">Remember me for 30 days
|
||||
<input type="checkbox" name="tlg_remember" id="tlg_remember">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="view-switch">Already have an account? <RouterLink class="rlink" to="/login">Sign in.</RouterLink></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.view-switch {
|
||||
text-align: center;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.rlink {
|
||||
text-decoration: none;
|
||||
color: var(--purple);
|
||||
font-weight: 700;
|
||||
}
|
||||
.rlink:hover {
|
||||
color: var(--purple-light);
|
||||
}
|
||||
.logo {
|
||||
display: block;
|
||||
margin: 1em auto 0em auto;
|
||||
}
|
||||
.container {
|
||||
padding: 2em 4em;
|
||||
background-color: var(--white-soft);
|
||||
border-radius: 5px;
|
||||
max-width: 440px;
|
||||
filter: drop-shadow(3px 6px 6px var(--color-drop-shadow));
|
||||
margin: auto;
|
||||
margin-top: 6vh;
|
||||
}
|
||||
.login {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.socials {
|
||||
margin: 3em 0em;
|
||||
}
|
||||
.socials > * {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
.separat-or {
|
||||
background-color: var(--white-soft);
|
||||
text-align: center;
|
||||
margin: 0px auto;
|
||||
margin-bottom: 3em;
|
||||
width: 90%;
|
||||
line-height: 0.1em;
|
||||
border-bottom: 2px solid var(--grey-light);
|
||||
}
|
||||
.separat-or span {
|
||||
background: var(--white-soft);
|
||||
padding:0 10px;
|
||||
}
|
||||
.remember {
|
||||
margin: 1em;
|
||||
margin-bottom: 2em;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* custom checkmark code from https://www.w3schools.com/howto/howto_css_custom_checkbox.asp */
|
||||
|
||||
/* Customize the label (the container) */
|
||||
.chk-container {
|
||||
display: block;
|
||||
position: relative;
|
||||
padding-left: 25px;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Hide the browser's default checkbox */
|
||||
.chk-container input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
height: 0;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
/* Create a custom checkbox */
|
||||
.checkmark {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 0;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
border-radius: 3px;
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
/* On mouse-over, add a grey background color */
|
||||
.chk-container:hover input ~ .checkmark {
|
||||
background-color: #bbb;
|
||||
}
|
||||
|
||||
/* When the checkbox is checked, add a blue background */
|
||||
.chk-container input:checked ~ .checkmark {
|
||||
background-color: var(--purple);
|
||||
}
|
||||
|
||||
/* Create the checkmark/indicator (hidden when not checked) */
|
||||
.checkmark:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Show the checkmark when checked */
|
||||
.chk-container input:checked ~ .checkmark:after {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Style the checkmark/indicator */
|
||||
.chk-container .checkmark:after {
|
||||
left: 7px;
|
||||
top: 3px;
|
||||
width: 5px;
|
||||
height: 10px;
|
||||
border: solid white;
|
||||
border-width: 0 2px 2px 0;
|
||||
-webkit-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div class="about">
|
||||
<h1>This is an about page</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
@media (min-width: 1024px) {
|
||||
.about {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"exclude": ["src/**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "@tsconfig/node18/tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*",
|
||||
"nightwatch.conf.*",
|
||||
"playwright.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
}
|
||||
}
|
||||
})
|
||||
Loading…
Reference in new issue