Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR | Hanko Vue Express Starter | Updated Starter -> Main #2

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions express-server/controllers/apiController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const asyncHandler = require("express-async-handler");

const sayValidated = asyncHandler(async (req, res) => {
res.status(200).send("<h1>You are validated.</h1>");
});

module.exports = {
sayValidated,
};
13 changes: 0 additions & 13 deletions express-server/controllers/helloController.js

This file was deleted.

14 changes: 0 additions & 14 deletions express-server/controllers/protectedController.js

This file was deleted.

77 changes: 47 additions & 30 deletions express-server/middleware/validateTokenHandler.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,51 @@
const jose = require("jose");
const dotenv = require("dotenv").config();

const JWKS = jose.createRemoteJWKSet(
new URL(`${process.env.HANKO_API_URL}/.well-known/jwks.json`)
);
const hankoApiUrl = process.env.HANKO_API_URL || '';

async function validateToken(req, res, next) {
let token = null;
if (
req.headers.authorization &&
req.headers.authorization.split(" ")[0] === "Bearer"
) {
token = req.headers.authorization.split(" ")[1];
} else if (req.cookies && req.cookies.hanko) {
token = req.cookies.hanko;
}
if (token === null || token.length === 0) {
res.status(401).send("Unauthorized");
return;
}
let authError = false;
await jose.jwtVerify(token, JWKS).catch((err) => {
authError = true;
console.log(err);
});
if (authError) {
res.status(401).send("Authentication Token not valid");
return;
}
next();
let token = null;
if ( req.headers.authorization && req.headers.authorization.split(" ")[0] === "Bearer"){
token = req.headers.authorization.split('')[1];
}
else if(req.cookies && req.cookies.hanko){
token = req.cookies.hanko;
}

if(token === null || token.lenth === 0){
res.status(401).send('Unauthorized');
console.log('could not find a token to validate');
return;
}

let authError = false;

const validationOptions = {
method: 'GET',
headers: {
'Cookie': `hanko=${token}` // If using cookie
// 'Authorization': `Bearer ${token}` // If using bearer header
}
}

const validationResponse = await fetch(hankoApiUrl + '/sessions/validate', validationOptions);

if(!validationResponse.ok){
authError = true;
}
else{
const validationData = await validationResponse.json();
if(!validationData.is_valid){
authError = true;
}
}

if(authError){
res.status(401).send('Unauthorized');
console.log('your token was not valid');
return;
}

console.log('validated');

next();
}

module.exports = validateToken;
module.exports = validateToken;
1,274 changes: 1,274 additions & 0 deletions express-server/package-lock.json

Large diffs are not rendered by default.

14 changes: 5 additions & 9 deletions express-server/package.json
Original file line number Diff line number Diff line change
@@ -8,18 +8,14 @@
"start": "node server.js",
"dev": "nodemon server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"cookie-parser": "^1.4.6",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"express-async-handler": "^1.2.0",
"jose": "^5.2.0"
"dotenv": "^16.4.7",
"express": "^4.21.2",
"express-async-handler": "^1.2.0"
},
"devDependencies": {
"nodemon": "^3.0.1"
"nodemon": "^3.1.9"
}
}
731 changes: 0 additions & 731 deletions express-server/pnpm-lock.yaml

This file was deleted.

6 changes: 6 additions & 0 deletions express-server/routes/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const express = require("express");
const router = express.Router()

router.use(require('../middleware/validateTokenHandler'))

module.exports = router;
9 changes: 0 additions & 9 deletions express-server/routes/helloRoute.js

This file was deleted.

11 changes: 0 additions & 11 deletions express-server/routes/protectedRoute.js

This file was deleted.

12 changes: 12 additions & 0 deletions express-server/routes/validate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const express = require("express");
const router = express.Router()

const {
sayValidated,
} = require('../controllers/apiController')

router.use(require('../middleware/validateTokenHandler'))

router.route('/').get(sayValidated);

module.exports = router;
22 changes: 15 additions & 7 deletions express-server/server.js
Original file line number Diff line number Diff line change
@@ -6,23 +6,31 @@ const cors = require('cors');
const app = new express();
const port = process.env.PORT || 5000;

//Makes sure only the frontend can make requests
app.use(cors({
origin: 'http://localhost:5173', // replace with your frontend's origin
credentials: true
}));

//two middleware functions
app.use(cookieParser());
app.use(express.json());

app.get("/", function (req, res) {
res.status(200).send("<h1>Hello world</h1>");

app.use(function(req, res, next) {
console.log('Page loaded')
next('route')
});

app.get("/", function (req, res) {
res.status(200).send("<h1>Hello World!</h1>");
});

app.use("/api/hello", require("./routes/helloRoute"));
app.use("/api/protected", require("./routes/protectedRoute"));
app.use("/api", require("./routes/api"));
app.use("/validate", require("./routes/validate"));


app.listen(port, () => {
console.log(`Server running on port ${port}`);
});

console.log(`Server running on port ${port}`);
});
15 changes: 0 additions & 15 deletions vue-frontend/.eslintrc.cjs

This file was deleted.

8 changes: 0 additions & 8 deletions vue-frontend/.prettierrc.json

This file was deleted.

7 changes: 1 addition & 6 deletions vue-frontend/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
{
"recommendations": [
"Vue.volar",
"Vue.vscode-typescript-vue-plugin",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
"recommendations": ["Vue.volar"]
}
5 changes: 5 additions & 0 deletions vue-frontend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Vue 3 + TypeScript + Vite

This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.

Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).
10 changes: 5 additions & 5 deletions vue-frontend/index.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<!DOCTYPE html>
<!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>
<meta charset="UTF-8" />
<link rel="icon" type="image/ico" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hanko Vue Express Starter</title>
</head>
<body>
<div id="app"></div>
1,446 changes: 1,446 additions & 0 deletions vue-frontend/package-lock.json

Large diffs are not rendered by default.

38 changes: 13 additions & 25 deletions vue-frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,35 +1,23 @@
{
"name": "vue-frontend",
"version": "0.0.0",
"name": "hanko-vue-frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"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/"
"build": "vue-tsc -b && vite build",
"preview": "vite preview"
},
"dependencies": {
"@teamhanko/hanko-elements": "^0.9.0",
"vue": "^3.3.4",
"vue-router": "^4.2.5"
"@teamhanko/hanko-elements": "^1.4.0",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
},
"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"
"@vitejs/plugin-vue": "^5.2.1",
"@vue/tsconfig": "^0.7.0",
"typescript": "~5.7.2",
"vite": "^6.2.0",
"vue-tsc": "^2.2.4"
}
}
2,201 changes: 0 additions & 2,201 deletions vue-frontend/pnpm-lock.yaml

This file was deleted.

Binary file added vue-frontend/public/expand.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified vue-frontend/public/favicon.ico
Binary file not shown.
Binary file added vue-frontend/public/userpfp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 2 additions & 4 deletions vue-frontend/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
<script setup lang="ts">
import { RouterView } from 'vue-router'
import { RouterView } from 'vue-router'
</script>

<template>
<RouterView />
<RouterView />
</template>

<style scoped></style>
Empty file removed vue-frontend/src/assets/base.css
Empty file.
1 change: 0 additions & 1 deletion vue-frontend/src/assets/logo.svg

This file was deleted.

5 changes: 0 additions & 5 deletions vue-frontend/src/assets/main.css

This file was deleted.

25 changes: 0 additions & 25 deletions vue-frontend/src/components/HankAuth.vue

This file was deleted.

17 changes: 0 additions & 17 deletions vue-frontend/src/components/HankoProfile.vue

This file was deleted.

11 changes: 0 additions & 11 deletions vue-frontend/src/components/HelloWorld.vue

This file was deleted.

28 changes: 28 additions & 0 deletions vue-frontend/src/components/hanko/HankoAuth.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script setup lang="ts">
import { useRouter } from "vue-router";
import { onMounted } from "vue";
import { register } from "@teamhanko/hanko-elements";
import "../../style/hanko-style.css"
const hankoApi = import.meta.env.VITE_HANKO_API_URL;
const router = useRouter();
const redirectAfterLogin = () => {
// successfully logged in, redirect to a page in your application
router.push("/dashboard");
};
onMounted(() => {
register(hankoApi)
.catch((error) => {
// handle error
console.log(error);
});
});
</script>

<template>
<hanko-auth @onSessionCreated="redirectAfterLogin" />
</template>
17 changes: 17 additions & 0 deletions vue-frontend/src/components/hanko/HankoProfile.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script setup lang="ts">
import { onMounted } from "vue";
import { register } from "@teamhanko/hanko-elements";
const hankoApi = import.meta.env.VITE_HANKO_API_URL;
onMounted(() => {
register(hankoApi).catch((error) => {
// handle error
console.log(error)
});
});
</script>

<template>
<hanko-profile />
</template>
Original file line number Diff line number Diff line change
@@ -10,12 +10,13 @@ const hanko = new Hanko(hankoApi);
const logout = () => {
hanko.user.logout().catch((error) => {
// handle error
console.log(error)
})
router.push("/login")
router.push("/")//Path user will be redirected to after logging out
}
</script>

<template>
<button @click="logout">Logout</button>
</template>
</template>
7 changes: 0 additions & 7 deletions vue-frontend/src/components/icons/IconCommunity.vue

This file was deleted.

7 changes: 0 additions & 7 deletions vue-frontend/src/components/icons/IconDocumentation.vue

This file was deleted.

7 changes: 0 additions & 7 deletions vue-frontend/src/components/icons/IconEcosystem.vue

This file was deleted.

7 changes: 0 additions & 7 deletions vue-frontend/src/components/icons/IconSupport.vue

This file was deleted.

19 changes: 0 additions & 19 deletions vue-frontend/src/components/icons/IconTooling.vue

This file was deleted.

20 changes: 20 additions & 0 deletions vue-frontend/src/components/starter/HankoStarterDashboard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script setup lang="ts">
import "../../style/hanko-starter-style.css"
import { Hanko } from "@teamhanko/hanko-elements";
const hankoApi = import.meta.env.VITE_HANKO_API_URL;
const hanko = new Hanko(hankoApi);
const email = (await hanko?.user.getCurrent())?.email
const id = (await hanko?.user.getCurrent())?.id
</script>

<template>
<div className='hankoStarterDashboard'>
<h1>Dashboard</h1><br />
<h2>Here is an example of how we can get user data using the Hanko Client.</h2>
<br />
<h3>Email: {{email}}</h3>
<h3>Id: {{id}}</h3>
</div>
</template>
33 changes: 33 additions & 0 deletions vue-frontend/src/components/starter/HankoStarterHeader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script setup lang="ts">
import { useRouter,useRoute } from "vue-router";
import { Hanko } from "@teamhanko/hanko-elements";
import LogoutButton from "../hanko/LogoutButton.vue";
import "../../style/hanko-starter-style.css"
const route = useRoute()
const router = useRouter();
const hankoApi = import.meta.env.VITE_HANKO_API_URL;
const hanko = new Hanko(hankoApi);
const email = (await hanko?.user.getCurrent())?.email
</script>

<template>
<div className='starterHeader'>
<div className='headerGap'></div>
<div className='userMenu'>
<div className='userInfo'>
<h1>{{email}}</h1>
<img src="/userpfp.png"/>
<img src="/expand.png" className='expandIcon'/>
</div>
<div className='userDropdown'>
<button @click="router.push('/profile')" v-if="route.path.includes('dashboard') ">Profile</button>
<button @click="router.push('/dashboard')" v-if="route.path.includes('profile') ">Dashboard</button>
<LogoutButton></LogoutButton>
</div>
</div>
</div>
</template>
24 changes: 24 additions & 0 deletions vue-frontend/src/components/starter/HankoStarterInfo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<script setup lang="ts">
import "../../style/hanko-starter-style.css"
</script>

<template>
<div className="starterInfo">
<h1>Hanko Vue starter.</h1>
<h2>
This repository is an example of an implementation of <span>Hanko</span> with <span>Vue</span> as frontend.
</h2>
<h2>
Trough the use of the <span>&lt;Hanko-Auth&gt;</span> and <span>&lt;Hanko-Profile&gt;</span> components you can quickly and effectively set up a Sign-In page or a User Profile page for your application.
</h2>
<h2>To create a <span>Hanko Project</span> please visit<br />
<a href="https://cloud.hanko.io/" rel="noreferrer" target='_blank'><span className='starterLink'>[ Hanko cloud console ]</span></a>
</h2>
<h2>To learn how to <span>set up an application like this</span> for yourself or just for more Information, please <br />
<a href="https://docs.hanko.io/" rel="noreferrer" target='_blank'><span className='starterLink'>[ Refer to our docs ]</span></a>
</h2>
<h2> <span>For more questions</span>, or if you want to join the Hanko community, please <br />
<a href="https://www.hanko.io/community" rel="noreferrer" target='_blank'><span className='starterLink'>[ Join our discord ]</span></a>
</h2>
</div>
</template>
7 changes: 3 additions & 4 deletions vue-frontend/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import './assets/main.css'

import { createApp } from 'vue'
import './style/globals.css'
import App from './App.vue'
import router from './router'
import router from './router/index'

const app = createApp(App)

app.use(router)

app.mount('#app')
app.mount('#app')
38 changes: 19 additions & 19 deletions vue-frontend/src/router/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '@/views/HomeView.vue'
import LoginView from '@/views/LoginView.vue'
import DashboardView from '@/views/DashboardView.vue'
import ProtectedView from '@/views/ProtectedView.vue'

import DashboardView from '../views/DashboardView.vue'
import ProfileView from '../views/ProfileView.vue'
import HomeView from '../views/HomeView.vue';

const securedRoutes = ["dashboard", "profile"];

async function isUserAuthenticated() {
try {
const response = await fetch('http://localhost:5001/api/protected', {
//Change this url to the url of your running hanko backend
const response = await fetch('http://localhost:5001/validate', {
credentials: 'include',
});
return response.ok;
@@ -23,31 +26,28 @@ const router = createRouter({
name: 'home',
component: HomeView
},
{
path: '/login',
name: 'login',
component: LoginView
},
{
path: '/dashboard',
name: 'dashboard',
component: DashboardView
component: DashboardView
},
{
path: '/protected',
name: 'protected',
component: ProtectedView
path: '/profile',
name: 'profile',
component: ProfileView
},
]
],
})


//Middleware that runs before each navigation
router.beforeEach(async (to, from, next) => {
if (to.name === 'protected' && !(await isUserAuthenticated())) {
next({ name: 'login' });
//Check if you are on a secure route
if (typeof to.name === "string" && securedRoutes.includes(to.name) && !(await isUserAuthenticated())) {
next({ name: 'home' }); //Name of the route to redirect to if user is not authenticated
} else {
next();
}
});

export default router

7 changes: 7 additions & 0 deletions vue-frontend/src/shims-vue.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// shims-vue.d.ts
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}

75 changes: 75 additions & 0 deletions vue-frontend/src/style/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/* Light mode color scheme */
:root {
--background: rgba(47, 91, 212, 0.015);
--backgroundGradient: white;
--foreground: #171717;
}

/* Dark mode color scheme */
@media (prefers-color-scheme: dark) {
:root {
--background: rgb(11, 16, 25);
--backgroundGradient: rgb(94, 14, 26);;
--foreground: #ededed;
}
}

html,
body {
max-width: 100vw;
overflow-x: hidden;
}

@media (max-aspect-ratio: 3/3) {
body{
padding-left: 0 !important;
}
}

body {
color: var(--foreground);

background: var(--background);
background: linear-gradient(120deg, var(--background) 30%, var(--backgroundGradient) 110%);

font-family: Arial, Helvetica, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;

padding-left: 37.5vw;

/* Center the items in the center */
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}

button{
width: 205px;
height: 6vh;
background-color: rgb(255, 255, 255);
color: rgb(36, 36, 36);
font-size: 150%;
font-weight: bold;
border-color: rgba(128, 128, 128, 0.404);
}

* {
box-sizing: border-box;
padding: 0;
margin: 0;
}

a {
color: inherit;
text-decoration: none;
}

@media (prefers-color-scheme: dark) {
html {
color-scheme: dark;
}
}

282 changes: 282 additions & 0 deletions vue-frontend/src/style/hanko-starter-style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
/* Light mode color sche,e */
:root {
--containerBackground: #ffffff7b;
--headerBackground: #0f0707;
--textColor: rgb(103, 103, 103);
--HightlightColor: rgb(47, 91, 212);
--HightlightColorFaded: rgba(47, 91, 212, 0.709);
}

/* Dark mode color scheme */
@media (prefers-color-scheme: dark) {
:root {
--containerBackground: rgba(0, 0, 0, 0.32);
--textColor: rgb(255, 255, 255);
--HightlightColor: rgb(255, 46, 76);
--HightlightColorFaded: rgba(255, 46, 77, 0.7);
}
.userMenu .userInfo img{
filter: invert() !important;
}
}

@media (max-aspect-ratio: 3/3) {
.starterInfo{
display: none !important;
}
.hankoStarterDashboard{
width: 100vw !important;
}

.starterHeader{
height: 10vh !important;
scale: 100% !important;
padding-right: 3vw !important;
}

body:has(.userInfo:hover){
padding-top: 20vh !important;
transition: 100ms;
}
body:has(.userInfo:active){
padding-top: 20vh !important;
transition: 100ms;
}
body:has(.starterHeader){
padding-top: 17h !important;
transition: 100ms;
}
}


.starterInfo{
position: absolute;
width: 37vw;
height: 100vh;
left: 0;
top: 0;
display: flex;
justify-content: center;
flex-direction: column;
gap: 45px;
padding: 4%;

background-color: var(--containerBackground);
}

.starterInfo > :nth-child(2){
padding-bottom: 60px;
}
.starterInfo > :nth-child(3){
padding-bottom: 130px;
}


.starterInfo h1{
color: var(--HightlightColor);
font-size: 2.1vw;
}
.starterInfo h2 span{
color: var(--HightlightColor);
}
.starterInfo h2{
font-size: 1.24vw;
color: var(--textColor);
}
.starterInfo button{
max-width: 50%;
height: 100%;
padding: 1.5%;
text-align: start;
background-color: transparent;
border: var(--HightlightColorFaded) solid 1.5px;
border-radius: 6px;
color: var(--HightlightColorFaded);
font-size: 140%;
margin-left: 10px;
transition: 400ms;
}

.starterInfo button:hover{
color: var(--textColor);
border: var(--HightlightColor) solid 1.5px;
box-shadow: var(--HightlightColor) 0px 0px 10px,var(--HightlightColorFaded) 0px 0px 20px inset;
transition: ease-out 150ms, box-shadow 500ms, border 300ms;
cursor: pointer;
}
.starterInfo button:active{
border: var(--textColor) solid 1.5px;
box-shadow: var(--textColor) 0px 0px 10px,rgba(255, 255, 255, 0.286) 0px 0px 20px inset;
transition: ease-out 20ms;
scale: 95%;
}
.starterInfo button{
width: fit-content;
}
.starterInfo div{
display: block;
gap: 10px;
}
.starterInfo div button{
padding-left: 5%;
padding-right: 5%;
}

.starterLink{
text-decoration: underline;
}

.starterLink:hover{
color: var(--textColor);
transition: 200ms;
text-shadow: var(--textColor) 0px 0px 10px;
}
.starterLink:active{
color: var(--HightlightColorFaded);
text-shadow: var(--HightlightColorFaded) 0px 0px 10px;
}

.hankoStarterDashboard{
width: 64vh;
height: fit-content;
max-width: 783px;
background-color: var(--containerBackground);

transition: 1ms;
display: flex;
justify-content: center;
flex-direction: column;
padding: 5%;
gap: 10px;

border: solid var(--containerBackground) 2px;
}

.hankoStarterDashboard h1{
font-size: 4.4vh;
color: var(--HightlightColor);
width: 100%;
}
.hankoStarterDashboard h2{
font-size: 2.25vh;
color: var(--textColor);
width: 100%;
}
.hankoStarterDashboard h3{
font-size: 2.4vh;
width: 100%;
color: var(--HightlightColor);
}
.starterHeader{
position: fixed;
right: 1vw;
top: 1vw;

width: 100%;
height: 8vh;

display: flex;
justify-content: end;
align-items: center;
padding-right: 2vw;

}

.userMenu{
box-sizing: border-box;

border-right: solid var(--HightlightColor);
border-radius: 5px;

height: 2.2vh;
}

.headerGap{
width: 5%;
}

.userMenu:hover{
height: 9.2vh;
margin-top: 7vh;
border-right: solid var(--HightlightColor);
transition: 100ms;
cursor: pointer;
}

.userMenu .userInfo{
display: flex;
}

.userMenu .userInfo img{
height: 2.4vh;
filter: invert() brightness(0.2);
}

.userMenu h1{
font-size: 23px;
height: 2.2vh;

border-radius: 5px;
padding: 0 12px 0 12px;

font-weight: lighter;

box-sizing: border-box;
}
.userMenu:hover h1{
border-right: none;
}
.userMenu .expandIcon{
scale: 60%;
padding-right: 5px;
}

.userMenu .userDropdown{
display: flex;
align-items: end;
flex-direction: column;
}
.userMenu:hover .userDropdown{
width: 100%;
height: 7vh;
padding-top: 0.5vh;
}
.userMenu .userDropdown button{
width: 0;
height: 0;
border: none;
font-size: 0;
margin-right: 12px;
background-color: transparent;
text-align: right;
}
.userMenu:hover .userDropdown button{
width: fit-content;
height: 3vh;
font-size: 23px;
color: var(--HightlightColorFaded);
padding-left: 6px;

transition: height 100ms;
transition: 100ms, margin-right 300ms;

}

.userMenu:hover .userDropdown button:hover{
color: var(--HightlightColor);
border-left: var(--HightlightColorFaded) solid;
border-radius: 3px;
margin-right: 24px;
transition: 100ms, margin-right 300ms;
cursor: pointer;
}

.userMenu:hover .userDropdown button:active{
color: var(--textColor);
border-left: var(--textColor) solid;
padding-left: 5px;
border-radius: 5px;
transition: padding-left 50ms;
scale: 95%;
cursor: pointer;
}
24 changes: 24 additions & 0 deletions vue-frontend/src/style/hanko-style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

/* For more information on customization of hanko elements go to https://docs.hanko.io/guides/hanko-elements/customize-appearance */

@media (prefers-color-scheme: dark) {
hanko-auth,
hanko-profile {
/* Color Scheme */
--color: #ffffff;
--color-shade-1: rgb(174, 135, 142);
--color-shade-2: rgba(226, 188, 193, 0.306);

--brand-color: rgb(255, 46, 76);
--brand-color-shade-1: rgb(255, 84, 109);
--brand-contrast-color: white;

--background-color: transparent;
--error-color: rgb(190, 48, 70);
--link-color: rgb(255, 46, 76);

}
hanko-auth::part(container){
--background-color: rgba(0, 0, 0, 0.32);
}
}
27 changes: 11 additions & 16 deletions vue-frontend/src/views/DashboardView.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
<script setup lang="ts">
import { useRouter } from 'vue-router'
const router = useRouter()
import HankoProfile from '@/components/HankoProfile.vue'
import LogoutButton from '@/components/LogoutButton.vue'
const navigateToProtected = () => {
router.push('/protected')
}
import HankoStarterHeader from '../components/starter/HankoStarterHeader.vue'
import HankoStarterInfo from '../components/starter/HankoStarterInfo.vue'
import HankoStarterDashboard from '../components/starter/HankoStarterDashboard.vue'
</script>

<template>
<main>
<HankoProfile />
<div>
<LogoutButton />
<button @click="navigateToProtected">Access the protected page</button>
</div>
<Suspense>
<HankoStarterHeader/>
</Suspense>
<Suspense>
<HankoStarterDashboard/>
</Suspense>
<HankoStarterInfo/>
</main>
</template>
11 changes: 4 additions & 7 deletions vue-frontend/src/views/HomeView.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
<script setup lang="ts">
import { useRouter } from 'vue-router'
const router = useRouter()
const navigateToLogin = () => {
router.push('/login')
}
import HankoAuth from '../components/hanko/HankoAuth.vue'
import HankoStarterInfo from '../components/starter/HankoStarterInfo.vue'
</script>

<template>
<main>
<button @click="navigateToLogin">Login</button>
<HankoAuth/>
<HankoStarterInfo/>
</main>
</template>
10 changes: 0 additions & 10 deletions vue-frontend/src/views/LoginView.vue

This file was deleted.

15 changes: 15 additions & 0 deletions vue-frontend/src/views/ProfileView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script setup lang="ts">
import HankoStarterHeader from '../components/starter/HankoStarterHeader.vue'
import HankoStarterInfo from '../components/starter/HankoStarterInfo.vue'
import HankoProfile from '../components/hanko/HankoProfile.vue';
</script>

<template>
<main>
<Suspense>
<HankoStarterHeader/>
</Suspense>
<HankoStarterInfo/>
<HankoProfile></HankoProfile>
</main>
</template>
10 changes: 0 additions & 10 deletions vue-frontend/src/views/ProtectedView.vue

This file was deleted.

File renamed without changes.
18 changes: 10 additions & 8 deletions vue-frontend/tsconfig.app.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}
8 changes: 2 additions & 6 deletions vue-frontend/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
32 changes: 20 additions & 12 deletions vue-frontend/tsconfig.node.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
{
"extends": "@tsconfig/node18/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*"
],
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}
19 changes: 5 additions & 14 deletions vue-frontend/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue({
template: {
plugins: [vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('hanko-')
isCustomElement: (tag) => tag.startsWith("hanko-")
}
}
})
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})],
})