mirror of
https://github.com/1f349/admin.1f349.com.git
synced 2024-11-12 14:41:34 +00:00
Start working on violet panel
This commit is contained in:
parent
ac116af353
commit
f645402b76
36
.editorconfig
Normal file
36
.editorconfig
Normal file
@ -0,0 +1,36 @@
|
||||
# EditorConfig is awesome: https://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Defaults
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
# CSS
|
||||
[*.css]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# HTML
|
||||
[*.{htm,html}]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# GNU make
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
# Svelte
|
||||
[*.svelte]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
|
||||
# YAML
|
||||
[*.{yaml,yml}]
|
||||
indent_size = 2
|
||||
indent_style = space
|
4
.env.production
Normal file
4
.env.production
Normal file
@ -0,0 +1,4 @@
|
||||
VITE_SSO_ORIGIN=https://sso.1f349.net
|
||||
|
||||
VITE_API_VIOLET=https://api.1f349.net/v1/violet
|
||||
VITE_API_ORCHID=https://api.1f349.net/v1/orchid
|
25
.github/workflows/build.yml
vendored
Normal file
25
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
name: Build/release
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Node.js, NPM and Yarn
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- run: yarn
|
||||
- run: yarn build
|
||||
|
||||
- name: Archive
|
||||
run: tar -czvf upload.tar.gz -C ./dist .
|
||||
|
||||
- name: Release
|
||||
run: 'curl -X POST -H "Authorization: Bearer ${{ secrets.DEPLOY }}" -F "upload=@upload.tar.gz" "https://sites.1f349.net/u?site=admin.1f349.net&branch=${{ github.ref_name }}"'
|
13
.prettierrc
Normal file
13
.prettierrc
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"printWidth": 150,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "all",
|
||||
"bracketSpacing": false,
|
||||
"bracketSameLine": false,
|
||||
"arrowParens": "avoid",
|
||||
"requirePragma": false,
|
||||
"insertPragma": false
|
||||
}
|
14
index.html
14
index.html
@ -1,10 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Svelte + TS</title>
|
||||
<title>1f349 Admin Dashboard</title>
|
||||
<meta name="author" content="1f349.net" />
|
||||
<meta property="og:title" content="1f349 Admin Dashboard" />
|
||||
<meta property="og:url" content="https://admin.1f349.net" />
|
||||
<meta property="og:type" content="object" />
|
||||
<meta property="og:image" content="https://admin.1f349.net/1f349.svg" />
|
||||
<meta property="og:site_name" content="1f349 Admin Dashboard" />
|
||||
<link rel="icon" type="image/svg+xml" href="/1f349.svg" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
@ -4,6 +4,8 @@
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"prettier:check:ci": "./node_modules/.bin/prettier --check .",
|
||||
"format": "./node_modules/.bin/prettier --write .",
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
@ -12,6 +14,7 @@
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
||||
"@tsconfig/svelte": "^5.0.0",
|
||||
"sass": "^1.69.4",
|
||||
"svelte": "^4.0.5",
|
||||
"svelte-check": "^3.4.6",
|
||||
"tslib": "^2.6.0",
|
||||
|
7
public/1f349.svg
Normal file
7
public/1f349.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36">
|
||||
<path fill="#5C913B" d="M2.472 6.572C1.528 8.698 1 11.038 1 13.5 1 23.165 9.059 31 19 31c7.746 0 14.33-4.767 16.868-11.44L2.472 6.572z"/>
|
||||
<path fill="#FFE8B6" d="M4.332 7.295C3.479 9.197 3 11.293 3 13.5c0 8.591 7.164 15.556 16 15.556 6.904 0 12.77-4.26 15.013-10.218L4.332 7.295z"/>
|
||||
<path fill="#DD2E44" d="M6.191 8.019C5.43 9.697 5 11.548 5 13.5c0 7.518 6.268 13.611 14 13.611 6.062 0 11.21-3.753 13.156-8.995L6.191 8.019z"/>
|
||||
<path d="M9.916 14.277c-.307.46-.741.708-.971.555-.23-.153-.168-.649.139-1.109.307-.46.741-.708.971-.555.23.153.168.649-.139 1.109zm6 1c-.307.46-.741.708-.971.555-.23-.153-.168-.649.139-1.109.307-.46.741-.708.971-.555.23.153.168.649-.139 1.109zm5.082 4.678c.05.551-.132 1.016-.406 1.041-.275.025-.538-.4-.588-.951-.051-.551.132-1.016.406-1.04.275-.026.538.398.588.95zm-9-2c.05.551-.132 1.016-.406 1.041-.275.025-.538-.4-.588-.951-.05-.551.132-1.016.406-1.04.276-.026.538.398.588.95zm3.901 5.346c-.333.441-.78.663-1 .497-.221-.166-.129-.658.205-1.099.333-.441.781-.663 1-.497.221.166.13.657-.205 1.099zm8.036.454c.273.481.299.979.06 1.115-.241.137-.656-.143-.929-.624-.273-.48-.299-.979-.059-1.115.241-.138.655.141.928.624zm-7.017-5.028c.303.463.362.958.131 1.109-.231.152-.663-.1-.966-.562-.303-.462-.361-.958-.131-1.108.231-.154.663.097.966.561zm8.981 1.574c-.333.441-.78.663-1.001.497-.221-.166-.129-.658.205-1.099.333-.442.78-.663 1-.497.222.166.131.657-.204 1.099z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
Before Width: | Height: | Size: 1.5 KiB |
186
src/App.svelte
186
src/App.svelte
@ -1,47 +1,161 @@
|
||||
<script lang="ts">
|
||||
import svelteLogo from './assets/svelte.svg'
|
||||
import viteLogo from '/vite.svg'
|
||||
import Counter from './lib/Counter.svelte'
|
||||
import type {SvelteComponent} from "svelte";
|
||||
import GeneralView from "./views/GeneralView.svelte";
|
||||
import VioletView from "./views/VioletView.svelte";
|
||||
import OrchidView from "./views/OrchidView.svelte";
|
||||
import {loginStore} from "./stores/login";
|
||||
import {openLoginPopup} from "./utils/login-popup";
|
||||
|
||||
let sidebarOptions: Array<{name: string; view: typeof SvelteComponent<{}>}> = [
|
||||
{name: "General", view: GeneralView},
|
||||
{name: "Violet", view: VioletView},
|
||||
{name: "Orchid", view: OrchidView},
|
||||
];
|
||||
let sidebarSelection: {name: string; view: typeof SvelteComponent<{}>} = sidebarOptions[0];
|
||||
|
||||
let tokenPerms: string[] = [];
|
||||
$: tokenPerms = [];
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<header>
|
||||
<div>
|
||||
<a href="https://vitejs.dev" target="_blank" rel="noreferrer">
|
||||
<img src={viteLogo} class="logo" alt="Vite Logo" />
|
||||
</a>
|
||||
<a href="https://svelte.dev" target="_blank" rel="noreferrer">
|
||||
<img src={svelteLogo} class="logo svelte" alt="Svelte Logo" />
|
||||
</a>
|
||||
<h1>🍉 - 1f349 Admin Dashboard</h1>
|
||||
</div>
|
||||
<h1>Vite + Svelte</h1>
|
||||
|
||||
<div class="card">
|
||||
<Counter />
|
||||
<div class="flex-gap" />
|
||||
<div class="nav-link">
|
||||
<a href="https://status.1f349.net" target="_blank">Status</a>
|
||||
</div>
|
||||
{#if $loginStore == null}
|
||||
<div class="login-view">
|
||||
<button on:click={() => openLoginPopup()}>Login</button>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="user-view">
|
||||
<img class="user-avatar" src={$loginStore.userinfo.picture} alt="{$loginStore.userinfo.name}'s profile picture" />
|
||||
<div class="user-display-name">{$loginStore.userinfo.name}</div>
|
||||
<button
|
||||
on:click={() => {
|
||||
$loginStore = null;
|
||||
localStorage.removeItem("login-session");
|
||||
}}>Logout</button
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
</header>
|
||||
<main>
|
||||
<div id="sidebar">
|
||||
{#each sidebarOptions as item (item.name)}
|
||||
<button class="sidebar-item" on:click={() => (sidebarSelection = item)} class:selected={item == sidebarSelection}>{item.name}</button>
|
||||
{/each}
|
||||
</div>
|
||||
<div id="option-view">
|
||||
<h2>{sidebarSelection.name}</h2>
|
||||
{#if $loginStore == null}
|
||||
<div>Please login to continue</div>
|
||||
{:else}
|
||||
<svelte:component this={sidebarSelection.view} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Check out <a href="https://github.com/sveltejs/kit#readme" target="_blank" rel="noreferrer">SvelteKit</a>, the official Svelte app framework powered by Vite!
|
||||
</p>
|
||||
|
||||
<p class="read-the-docs">
|
||||
Click on the Vite and Svelte logos to learn more
|
||||
</p>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
<style lang="scss">
|
||||
header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 70px;
|
||||
padding: 0 32px;
|
||||
background-color: #2c2c2c;
|
||||
box-shadow: 0 4px 8px #0003, 0 6px 20px #00000030;
|
||||
gap: 16px;
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
|
||||
h1 {
|
||||
font-size: 32px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.flex-gap {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.user-view {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
|
||||
.user-avatar {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
button,
|
||||
a {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
box-sizing: border-box;
|
||||
color: tomato;
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 24px;
|
||||
padding: 8px;
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
}
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
.logo.svelte:hover {
|
||||
filter: drop-shadow(0 0 2em #ff3e00aa);
|
||||
}
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
align-items: stretch;
|
||||
height: calc(100% - 70px);
|
||||
|
||||
#sidebar {
|
||||
width: 200px;
|
||||
|
||||
button {
|
||||
background-color: #2c2c2c;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
box-sizing: border-box;
|
||||
color: tomato;
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 24px;
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
|
||||
&:hover {
|
||||
background-color: #1c1c1c;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: #1c1c1c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#option-view {
|
||||
box-sizing: border-box;
|
||||
padding: 16px;
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
flex-grow: 1;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
80
src/app.css
80
src/app.css
@ -1,80 +0,0 @@
|
||||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
46
src/app.scss
Normal file
46
src/app.scss
Normal file
@ -0,0 +1,46 @@
|
||||
$theme-text: rgba(255, 255, 255, 0.87);
|
||||
$theme-bg: #242424;
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
$theme-text: #213547;
|
||||
$theme-bg: #ffffff;
|
||||
}
|
||||
|
||||
:root {
|
||||
font-family: Ubuntu, Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: normal;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: $theme-text;
|
||||
background-color: $theme-bg;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
#app {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-content: stretch;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: tomato;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: tomato;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="26.6" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 308"><path fill="#FF3E00" d="M239.682 40.707C211.113-.182 154.69-12.301 113.895 13.69L42.247 59.356a82.198 82.198 0 0 0-37.135 55.056a86.566 86.566 0 0 0 8.536 55.576a82.425 82.425 0 0 0-12.296 30.719a87.596 87.596 0 0 0 14.964 66.244c28.574 40.893 84.997 53.007 125.787 27.016l71.648-45.664a82.182 82.182 0 0 0 37.135-55.057a86.601 86.601 0 0 0-8.53-55.577a82.409 82.409 0 0 0 12.29-30.718a87.573 87.573 0 0 0-14.963-66.244"></path><path fill="#FFF" d="M106.889 270.841c-23.102 6.007-47.497-3.036-61.103-22.648a52.685 52.685 0 0 1-9.003-39.85a49.978 49.978 0 0 1 1.713-6.693l1.35-4.115l3.671 2.697a92.447 92.447 0 0 0 28.036 14.007l2.663.808l-.245 2.659a16.067 16.067 0 0 0 2.89 10.656a17.143 17.143 0 0 0 18.397 6.828a15.786 15.786 0 0 0 4.403-1.935l71.67-45.672a14.922 14.922 0 0 0 6.734-9.977a15.923 15.923 0 0 0-2.713-12.011a17.156 17.156 0 0 0-18.404-6.832a15.78 15.78 0 0 0-4.396 1.933l-27.35 17.434a52.298 52.298 0 0 1-14.553 6.391c-23.101 6.007-47.497-3.036-61.101-22.649a52.681 52.681 0 0 1-9.004-39.849a49.428 49.428 0 0 1 22.34-33.114l71.664-45.677a52.218 52.218 0 0 1 14.563-6.398c23.101-6.007 47.497 3.036 61.101 22.648a52.685 52.685 0 0 1 9.004 39.85a50.559 50.559 0 0 1-1.713 6.692l-1.35 4.116l-3.67-2.693a92.373 92.373 0 0 0-28.037-14.013l-2.664-.809l.246-2.658a16.099 16.099 0 0 0-2.89-10.656a17.143 17.143 0 0 0-18.398-6.828a15.786 15.786 0 0 0-4.402 1.935l-71.67 45.674a14.898 14.898 0 0 0-6.73 9.975a15.9 15.9 0 0 0 2.709 12.012a17.156 17.156 0 0 0 18.404 6.832a15.841 15.841 0 0 0 4.402-1.935l27.345-17.427a52.147 52.147 0 0 1 14.552-6.397c23.101-6.006 47.497 3.037 61.102 22.65a52.681 52.681 0 0 1 9.003 39.848a49.453 49.453 0 0 1-22.34 33.12l-71.664 45.673a52.218 52.218 0 0 1-14.563 6.398"></path></svg>
|
Before Width: | Height: | Size: 1.9 KiB |
@ -1,10 +0,0 @@
|
||||
<script lang="ts">
|
||||
let count: number = 0
|
||||
const increment = () => {
|
||||
count += 1
|
||||
}
|
||||
</script>
|
||||
|
||||
<button on:click={increment}>
|
||||
count is {count}
|
||||
</button>
|
@ -1,4 +1,4 @@
|
||||
import './app.css'
|
||||
import './app.scss'
|
||||
import App from './App.svelte'
|
||||
|
||||
const app = new App({
|
||||
|
28
src/stores/login.ts
Normal file
28
src/stores/login.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import {writable} from "svelte/store";
|
||||
|
||||
export interface LoginStore {
|
||||
userinfo: {
|
||||
email: string;
|
||||
name: string;
|
||||
sub: string;
|
||||
picture: string;
|
||||
};
|
||||
tokens: {
|
||||
access: string;
|
||||
refresh: string;
|
||||
};
|
||||
}
|
||||
|
||||
export const loginStore = writable<LoginStore | null>(
|
||||
(() => {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem("login-session") || "");
|
||||
} catch (_) {
|
||||
return null;
|
||||
}
|
||||
})(),
|
||||
);
|
||||
|
||||
loginStore.subscribe(x => {
|
||||
localStorage.setItem("login-session", JSON.stringify(x));
|
||||
});
|
53
src/utils/login-popup.ts
Normal file
53
src/utils/login-popup.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import {loginStore} from "../stores/login";
|
||||
|
||||
let currentLoginPopup: {close: () => void} | null = null;
|
||||
|
||||
const ssoOrigin = import.meta.env.VITE_SSO_ORIGIN;
|
||||
|
||||
window.addEventListener("message", function (event) {
|
||||
if (event.origin !== ssoOrigin) return;
|
||||
if (isObject(event.data)) {
|
||||
loginStore.set(event.data);
|
||||
if (currentLoginPopup) currentLoginPopup.close();
|
||||
return;
|
||||
}
|
||||
alert("Failed to log user in: the login data was probably corrupted");
|
||||
});
|
||||
|
||||
function isObject(obj: Object) {
|
||||
return obj != null && obj.constructor.name === "Object";
|
||||
}
|
||||
|
||||
function popupCenterScreen(url: string, title: string, w: number, h: number, focus: boolean) {
|
||||
const top = (screen.availHeight - h) / 4,
|
||||
left = (screen.availWidth - w) / 2;
|
||||
const popup = openWindow(url, title, `scrollbars=yes,width=${w},height=${h},top=${top},left=${left}`);
|
||||
if (focus === true && window.focus !== undefined && popup !== null) popup.focus();
|
||||
return popup;
|
||||
}
|
||||
|
||||
function openWindow(url: string | URL, winnm: string, options: string): Window | null {
|
||||
var wTop = firstAvailableValue([window.screen.availTop, window.screenY, window.screenTop, 0]);
|
||||
var wLeft = firstAvailableValue([window.screen.availLeft, window.screenX, window.screenLeft, 0]);
|
||||
let w: Window | null;
|
||||
var top = 0,
|
||||
left = 0;
|
||||
var result;
|
||||
if ((result = /top=(\d+)/g.exec(options))) top = parseInt(result[1]);
|
||||
if ((result = /left=(\d+)/g.exec(options))) left = parseInt(result[1]);
|
||||
if (options) {
|
||||
options = options.replace("top=" + top, "top=" + (top + wTop));
|
||||
options = options.replace("left=" + left, "left=" + (left + wLeft));
|
||||
w = window.open(url, winnm, options);
|
||||
} else w = window.open(url, winnm);
|
||||
return w;
|
||||
}
|
||||
|
||||
function firstAvailableValue(arr: any) {
|
||||
for (var i = 0; i < arr.length; i++) if (typeof arr[i] != "undefined") return arr[i];
|
||||
}
|
||||
|
||||
export function openLoginPopup() {
|
||||
if (currentLoginPopup) currentLoginPopup.close();
|
||||
currentLoginPopup = popupCenterScreen(ssoOrigin + "/popup?origin=" + encodeURIComponent(location.origin), "Login with 1f349 SSO", 500, 500, false);
|
||||
}
|
1
src/views/GeneralView.svelte
Normal file
1
src/views/GeneralView.svelte
Normal file
@ -0,0 +1 @@
|
||||
<div>No options available here</div>
|
1
src/views/OrchidView.svelte
Normal file
1
src/views/OrchidView.svelte
Normal file
@ -0,0 +1 @@
|
||||
<div>No options available here: {import.meta.env.VITE_API_ORCHID}</div>
|
36
src/views/VioletView.svelte
Normal file
36
src/views/VioletView.svelte
Normal file
@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import {loginStore, type LoginStore} from "../stores/login";
|
||||
|
||||
const apiViolet = import.meta.env.VITE_API_VIOLET;
|
||||
|
||||
let promiseForRoutes = new Promise(async (res, rej) => {
|
||||
fetch(apiViolet + "/route", {headers: {Authorization: "Bearer " + ($loginStore as LoginStore).tokens.access}})
|
||||
.then(x => {
|
||||
if(x.status!==200) throw new Error("Unexpected status code: " + x.status);
|
||||
return x.json();
|
||||
})
|
||||
.then(x => res(x))
|
||||
.catch(x => rej(x));
|
||||
});
|
||||
</script>
|
||||
|
||||
{#await promiseForRoutes}
|
||||
<div>Loading...</div>
|
||||
{:then allRoutes}
|
||||
<table>
|
||||
<tr>
|
||||
<th>Source</th>
|
||||
<th>Destination</th>
|
||||
<th>Flags</th>
|
||||
<th>Active</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td />
|
||||
<td />
|
||||
<td />
|
||||
<td />
|
||||
</tr>
|
||||
</table>
|
||||
{:catch err}
|
||||
<div>{err}</div>
|
||||
{/await}
|
10
src/vite-env.d.ts
vendored
10
src/vite-env.d.ts
vendored
@ -1,2 +1,12 @@
|
||||
/// <reference types="svelte" />
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
VITE_SSO_ORIGIN: string;
|
||||
VITE_API_VIOLET: string;
|
||||
VITE_API_ORCHID: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
|
18
yarn.lock
18
yarn.lock
@ -270,7 +270,7 @@ callsites@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
|
||||
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
|
||||
|
||||
chokidar@^3.4.1:
|
||||
"chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.1:
|
||||
version "3.5.3"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
|
||||
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
|
||||
@ -430,6 +430,11 @@ graceful-fs@^4.1.3:
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
||||
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||
|
||||
immutable@^4.0.0:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.4.tgz#2e07b33837b4bb7662f288c244d1ced1ef65a78f"
|
||||
integrity sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==
|
||||
|
||||
import-fresh@^3.2.1:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
|
||||
@ -675,6 +680,15 @@ sander@^0.5.0:
|
||||
mkdirp "^0.5.1"
|
||||
rimraf "^2.5.2"
|
||||
|
||||
sass@^1.69.4:
|
||||
version "1.69.4"
|
||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.69.4.tgz#10c735f55e3ea0b7742c6efa940bce30e07fbca2"
|
||||
integrity sha512-+qEreVhqAy8o++aQfCJwp0sklr2xyEzkm9Pp/Igu9wNPoe7EZEQ8X/MBvvXggI2ql607cxKg/RKOwDj6pp2XDA==
|
||||
dependencies:
|
||||
chokidar ">=3.0.0 <4.0.0"
|
||||
immutable "^4.0.0"
|
||||
source-map-js ">=0.6.2 <2.0.0"
|
||||
|
||||
sorcery@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/sorcery/-/sorcery-0.11.0.tgz#310c80ee993433854bb55bb9aa4003acd147fca8"
|
||||
@ -685,7 +699,7 @@ sorcery@^0.11.0:
|
||||
minimist "^1.2.0"
|
||||
sander "^0.5.0"
|
||||
|
||||
source-map-js@^1.0.1, source-map-js@^1.0.2:
|
||||
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
|
||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||
|
Loading…
Reference in New Issue
Block a user