Making every thing nicer
13
src/Icons/Account.svelte
Normal file
@ -0,0 +1,13 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="feather feather-user"><path
|
||||
d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
|
||||
<circle cx="12" cy="7" r="4" /></svg>
|
After Width: | Height: | Size: 329 B |
1
src/Icons/Admin.svelte
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-tool"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"></path></svg>
|
After Width: | Height: | Size: 386 B |
1
src/Icons/Apps.svelte
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-grid"><rect x="3" y="3" width="7" height="7"></rect><rect x="14" y="3" width="7" height="7"></rect><rect x="14" y="14" width="7" height="7"></rect><rect x="3" y="14" width="7" height="7"></rect></svg>
|
After Width: | Height: | Size: 404 B |
12
src/Icons/Darktheme.svelte
Normal file
@ -0,0 +1,12 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="feather feather-moon"><path
|
||||
d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" /></svg>
|
After Width: | Height: | Size: 301 B |
13
src/Icons/Home.svelte
Normal file
@ -0,0 +1,13 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="feather feather-home"><path
|
||||
d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
||||
<polyline points="9 22 9 12 15 12 15 22" /></svg>
|
After Width: | Height: | Size: 346 B |
16
src/Icons/Menu.svelte
Normal file
@ -0,0 +1,16 @@
|
||||
<svg
|
||||
id="Layer_1"
|
||||
style="enable-background:new 0 0 32 32;"
|
||||
version="1.1"
|
||||
viewBox="0 0 32 32"
|
||||
width="32px"
|
||||
xml:space="preserve"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<path
|
||||
d="M4,10h24c1.104,0,2-0.896,2-2s-0.896-2-2-2H4C2.896,6,2,6.896,2,8S2.896,10,4,10z
|
||||
M28,14H4c-1.104,0-2,0.896-2,2
|
||||
s0.896,2,2,2h24c1.104,0,2-0.896,2-2S29.104,14,28,14z
|
||||
M28,22H4c-1.104,0-2,0.896-2,2s0.896,2,2,2h24c1.104,0,2-0.896,2-2
|
||||
S29.104,22,28,22z" />
|
||||
</svg>
|
After Width: | Height: | Size: 494 B |
1
src/Icons/Security.svelte
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-shield"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path></svg>
|
After Width: | Height: | Size: 279 B |
@ -1,3 +1,7 @@
|
||||
<script lang="typescript">
|
||||
import Theme from "../../components/theme";
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.main {
|
||||
padding: 2rem;
|
||||
@ -11,34 +15,35 @@
|
||||
li > a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
:root {
|
||||
--primary: yellow;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="main">
|
||||
<h1>Home Page</h1>
|
||||
<Theme dark={true}>
|
||||
<div class="main">
|
||||
<h1>Home Page</h1>
|
||||
|
||||
<h2>About</h2>
|
||||
<p>
|
||||
OpenAuth is a Service to provide simple Authentication to a veriaty of
|
||||
Applications. With a simple to use API and different Strategies, it can be
|
||||
easily integrated into most Applications.
|
||||
</p>
|
||||
<h2>About</h2>
|
||||
<p>
|
||||
OpenAuth is a Service to provide simple Authentication to a veriaty of
|
||||
Applications. With a simple to use API and different Strategies, it can be
|
||||
easily integrated into most Applications.
|
||||
</p>
|
||||
|
||||
<h2>QickLinks</h2>
|
||||
<p>
|
||||
If you want to manage your Account, click
|
||||
<a href="user.html">here</a>
|
||||
</p>
|
||||
<h2>QickLinks</h2>
|
||||
<p>If you want to manage your Account, click <a href="/user">here</a></p>
|
||||
|
||||
<h2>Applications using OpenAuth</h2>
|
||||
<h2>Applications using OpenAuth</h2>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://ebook.stamm.me">EBook Store and Reader</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://notes.hibas123.de">
|
||||
Secure and Simple Notes application
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul>
|
||||
<li><a href="https://ebook.stamm.me">EBook Store and Reader</a></li>
|
||||
<li>
|
||||
<a href="https://notes.hibas123.de">
|
||||
Secure and Simple Notes application
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</Theme>
|
||||
|
@ -4,5 +4,3 @@ import App from "./App.svelte";
|
||||
new App({
|
||||
target: document.body,
|
||||
});
|
||||
|
||||
export default app;
|
||||
|
@ -1,28 +1,77 @@
|
||||
<script>
|
||||
import HomePage from "./Pages/Home.svelte";
|
||||
import AccountPage from "./Pages/Account.svelte";
|
||||
import SecurityPage from "./Pages/Security.svelte";
|
||||
import AppsPage from "./Pages/Apps.svelte";
|
||||
import { slide, fade } from "svelte/transition";
|
||||
import HomeIcon from "../../Icons/Home.svelte";
|
||||
import AccountIcon from "../../Icons/Account.svelte";
|
||||
import SecurityIcon from "../../Icons/Security.svelte";
|
||||
import AppsIcon from "../../Icons/Apps.svelte";
|
||||
import AdminIcon from "../../Icons/Admin.svelte";
|
||||
import MenuIcon from "../../Icons/Menu.svelte";
|
||||
import DarkthemeIcon from "../../Icons/Darktheme.svelte";
|
||||
|
||||
const pages = [
|
||||
import { isAdmin } from "./api";
|
||||
|
||||
let dark = localStorage.getItem("theme") === "dark";
|
||||
|
||||
$: {
|
||||
localStorage.setItem("theme", dark ? "dark" : "light");
|
||||
}
|
||||
|
||||
let pages = [
|
||||
{
|
||||
id: "home",
|
||||
title: "Home",
|
||||
icon: HomeIcon,
|
||||
component: HomePage,
|
||||
},
|
||||
{
|
||||
id: "account",
|
||||
title: "Account",
|
||||
icon:
|
||||
"data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjMDAwMDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpza2V0Y2g9Imh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaC9ucyIgdmlld0JveD0iMCAwIDUwMCA1MDAiIHZlcnNpb249IjEuMSIgeD0iMHB4IiB5PSIwcHgiPjx0aXRsZT4wMSBAZnVsbHdpZHRoPC90aXRsZT48ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz48ZyBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBza2V0Y2g6dHlwZT0iTVNQYWdlIj48ZyBza2V0Y2g6dHlwZT0iTVNBcnRib2FyZEdyb3VwIiBmaWxsPSIjMDAwMDAwIj48cGF0aCBkPSJNNDU3LjUsMjUwIEM0NTcuNSwxMzUuOTUzMTk5IDM2NS4wNDY4MDEsNDMuNSAyNTEsNDMuNSBDMTM2Ljk1MzE5OSw0My41IDQ0LjUsMTM1Ljk1MzE5OSA0NC41LDI1MCBDNDQuNSwzNjQuMDQ2ODAxIDEzNi45NTMxOTksNDU2LjUgMjUxLDQ1Ni41IEMzNjUuMDQ2ODAxLDQ1Ni41IDQ1Ny41LDM2NC4wNDY4MDEgNDU3LjUsMjUwIFogTTU3LjUsMjUwIEM1Ny41LDE0My4xMzI5MDEgMTQ0LjEzMjkwMSw1Ni41IDI1MSw1Ni41IEMzNTcuODY3MDk5LDU2LjUgNDQ0LjUsMTQzLjEzMjkwMSA0NDQuNSwyNTAgQzQ0NC41LDM1Ni44NjcwOTkgMzU3Ljg2NzA5OSw0NDMuNSAyNTEsNDQzLjUgQzE0NC4xMzI5MDEsNDQzLjUgNTcuNSwzNTYuODY3MDk5IDU3LjUsMjUwIFoiIHNrZXRjaDp0eXBlPSJNU1NoYXBlR3JvdXAiPjwvcGF0aD48cGF0aCBkPSJNMjUxLjUsMjUyLjkzMzk2MiBDMTk2Ljg1NDE5LDI1Mi45MzM5NjIgMTUyLjUsMjk2LjM2MDgwOSAxNTIuNSwzNTAgQzE1Mi41LDM1My41ODk4NTEgMTU1LjQxMDE0OSwzNTYuNSAxNTksMzU2LjUgTDM0NCwzNTYuNSBDMzQ3LjU4OTg1MSwzNTYuNSAzNTAuNSwzNTMuNTg5ODUxIDM1MC41LDM1MCBDMzUwLjUsMjk2LjM2MDgwOSAzMDYuMTQ1ODEsMjUyLjkzMzk2MiAyNTEuNSwyNTIuOTMzOTYyIFogTTE2NS41LDM0My41MDAwMDEgQzE2NS41LDMwMy42MDI3MDggMjAzLjk3MzEzMSwyNjUuOTMzOTYyIDI1MS41LDI2NS45MzM5NjIgQzI5OS4wMjY4NjksMjY1LjkzMzk2MiAzMzcuNSwzMDMuNjAyNzA4IDMzNy40OTk5OTcsMzQzLjUwMDAwMSBMMTY1LjUsMzQzLjUwMDAwMSBaIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj48L3BhdGg+PHBhdGggZD0iTTMwNC4yNSwxOTMuMzk2MjI2IEMzMDQuMjUsMTY1LjgwODIwMiAyODEuNDY1NDI0LDE0My41IDI1My40MjcwODMsMTQzLjUgQzIyNS4zODg3NDIsMTQzLjUgMjAyLjYwNDE2NywxNjUuODA4MjAyIDIwMi42MDQxNjcsMTkzLjM5NjIyNiBDMjAyLjYwNDE2NywyMjAuOTg0MjUgMjI1LjM4ODc0MiwyNDMuMjkyNDUzIDI1My40MjcwODMsMjQzLjI5MjQ1MyBDMjgxLjQ2NTQyNCwyNDMuMjkyNDUzIDMwNC4yNSwyMjAuOTg0MjUgMzA0LjI1LDE5My4zOTYyMjYgWiBNMjE1LjYwNDE2NywxOTMuMzk2MjI2IEMyMTUuNjA0MTY3LDE3My4wNTAxMDIgMjMyLjUwNzY4MywxNTYuNSAyNTMuNDI3MDgzLDE1Ni41IEMyNzQuMzQ2NDg0LDE1Ni41IDI5MS4yNSwxNzMuMDUwMTAyIDI5MS4yNSwxOTMuMzk2MjI2IEMyOTEuMjUsMjEzLjc0MjM1MSAyNzQuMzQ2NDg0LDIzMC4yOTI0NTMgMjUzLjQyNzA4MywyMzAuMjkyNDUzIEMyMzIuNTA3NjgzLDIzMC4yOTI0NTMgMjE1LjYwNDE2NywyMTMuNzQyMzUxIDIxNS42MDQxNjcsMTkzLjM5NjIyNiBaIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj48L3BhdGg+PC9nPjwvZz48L3N2Zz4=",
|
||||
component: AccountPage
|
||||
icon: AccountIcon,
|
||||
component: AccountPage,
|
||||
},
|
||||
{
|
||||
id: "security",
|
||||
title: "Security",
|
||||
icon:
|
||||
"data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9JzMwMHB4JyB3aWR0aD0nMzAwcHgnICBmaWxsPSIjMDAwMDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNTEyIDUxMjsiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwYXRoIGQ9Ik00NDUuOCwzNy4zYy0xLjItMC43LTIuNy0wLjgtMy45LTAuMWMtNC4zLDIuMi0xMS42LDMuNC0yMS45LDMuNGMtMzMuNiwwLTkwLjgtMTIuNC0xMjguNy0yMC41Yy0xNC0zLTI2LjEtNS42LTM0LjEtNyAgIGMtMC40LTAuMS0wLjktMC4xLTEuNCwwYy03LjIsMS4yLTE4LjUsMy42LTMxLjcsNi4zQzE4NC4zLDI3LjYsMTI0LjIsNDAsOTAuNiw0MGMtMTEuNiwwLTE3LTEuNS0xOS41LTIuOCAgIGMtMS4yLTAuNi0yLjctMC42LTMuOSwwLjFzLTEuOSwyLTEuOSwzLjRjMCw3My4xLDMuOCwxNjguNCwzMy45LDI1Ny43YzE0LjMsNDIuOCwzMy41LDgwLjcsNTcuMSwxMTIuNyAgIGMyNi42LDM2LDU5LjcsNjUuNyw5OC4zLDg4LjNjMC42LDAuNCwxLjMsMC41LDIsMC41czEuNC0wLjIsMi0wLjVjMzguNi0yMi42LDcxLjYtNTIuMyw5OC4yLTg4LjNjMjMuNi0zMiw0Mi45LTY5LjksNTcuMS0xMTIuNyAgIGMyOS41LTg3LjYsMzMuNy0xNzkuNCwzMy45LTI1Ny43QzQ0Ny43LDM5LjQsNDQ3LDM4LjEsNDQ1LjgsMzcuM3ogTTQwNi4zLDI5NS45Yy0yOS4zLDg4LjEtNzkuNywxNTMuOC0xNDkuOCwxOTUuNCAgIEMxODYuNCw0NDkuNywxMzYsMzg0LDEwNi43LDI5NS45Qzc3LjgsMjEwLDczLjQsMTE4LjEsNzMuMiw0Ni40YzQuNSwxLjEsMTAuMiwxLjYsMTcuMywxLjZjMCwwLDAsMCwwLDAgICBjMzQuNSwwLDk1LjEtMTIuNiwxMzUuMi0yMC45YzEyLjctMi42LDIzLjYtNC45LDMwLjctNi4xYzcuOCwxLjQsMTkuNSwzLjksMzMuMSw2LjhDMzMwLDM2LjYsMzg1LjUsNDguNiw0MjAsNDguNiAgIGM4LjEsMCwxNC43LTAuNywxOS43LTJDNDM5LjMsMTIyLjksNDM0LjcsMjExLjUsNDA2LjMsMjk1Ljl6Ij48L3BhdGg+PHBhdGggZD0iTTI1Ni41LDIxNy44YzQ1LDAsODEuNi0zNi42LDgxLjYtODEuNmMwLTQ1LTM2LjYtODEuNi04MS42LTgxLjZjLTQ1LDAtODEuNiwzNi42LTgxLjYsODEuNiAgIEMxNzQuOSwxODEuMiwyMTEuNSwyMTcuOCwyNTYuNSwyMTcuOHogTTI1Ni41LDYyLjZjNDAuNiwwLDczLjYsMzMsNzMuNiw3My42YzAsNDAuNi0zMyw3My42LTczLjYsNzMuNmMtNDAuNiwwLTczLjYtMzMtNzMuNi03My42ICAgQzE4Mi45LDk1LjYsMjE1LjksNjIuNiwyNTYuNSw2Mi42eiI+PC9wYXRoPjxwYXRoIGQ9Ik0zMDkuMiwyMjguOUgyMDMuOGMtMjYuNSwwLTQ4LDIxLjUtNDgsNDh2NzljMCwyLjIsMS44LDQsNCw0aDE5My40YzIuMiwwLDQtMS44LDQtNHYtNzkgICBDMzU3LjIsMjUwLjQsMzM1LjYsMjI4LjksMzA5LjIsMjI4Ljl6IE0zNDkuMiwzNTEuOUgxNjMuOHYtNzVjMC0yMiwxNy45LTQwLDQwLTQwaDEwNS40YzIyLjEsMCw0MCwxNy45LDQwLDQwTDM0OS4yLDM1MS45ICAgTDM0OS4yLDM1MS45eiI+PC9wYXRoPjwvZz48L3N2Zz4=",
|
||||
component: SecurityPage
|
||||
}
|
||||
icon: SecurityIcon,
|
||||
component: SecurityPage,
|
||||
},
|
||||
{
|
||||
id: "apps",
|
||||
title: "Applications",
|
||||
icon: AppsIcon,
|
||||
component: AppsPage,
|
||||
},
|
||||
];
|
||||
|
||||
isAdmin().then((admin) => {
|
||||
if (admin) {
|
||||
pages = [
|
||||
...pages,
|
||||
{
|
||||
id: "admin",
|
||||
title: "Admin",
|
||||
icon: AdminIcon,
|
||||
component: HomePage,
|
||||
divide: true,
|
||||
subComponents: [
|
||||
{
|
||||
id: "admin_user",
|
||||
title: "User",
|
||||
component: HomePage,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
function getPage() {
|
||||
let pageid = window.location.hash.slice(1);
|
||||
return pages.find(e => e.id === pageid) || pages[0];
|
||||
return pages.find((e) => e.id === pageid) || pages[0];
|
||||
}
|
||||
|
||||
let page = getPage();
|
||||
@ -33,14 +82,14 @@
|
||||
|
||||
const mq = window.matchMedia("(min-width: 45rem)");
|
||||
let sidebar_button = !mq.matches;
|
||||
mq.addEventListener("change", ev => {
|
||||
mq.addEventListener("change", (ev) => {
|
||||
sidebar_button = !ev.matches;
|
||||
});
|
||||
|
||||
let sidebar_active = false;
|
||||
|
||||
function setPage(pageid) {
|
||||
let pg = pages.find(e => e.id === pageid);
|
||||
let pg = pages.find((e) => e.id === pageid);
|
||||
if (!pg) {
|
||||
throw new Error("Invalid Page " + pageid);
|
||||
} else {
|
||||
@ -56,6 +105,7 @@
|
||||
let loading = true;
|
||||
|
||||
import NavigationBar from "./NavigationBar.svelte";
|
||||
import Theme from "../../components/theme/Theme.svelte";
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@ -72,9 +122,11 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.container {
|
||||
.app-container {
|
||||
display: grid;
|
||||
height: 100%;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow-x: hidden;
|
||||
grid-template-columns: auto 100%;
|
||||
grid-template-rows: 60px auto 60px;
|
||||
grid-template-areas:
|
||||
@ -88,6 +140,9 @@
|
||||
background-color: var(--primary);
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.header > h1 {
|
||||
@ -110,12 +165,14 @@
|
||||
background-color: rgba(255, 255, 255, 0.151);
|
||||
}
|
||||
|
||||
.header > .dark-theme-btn {
|
||||
}
|
||||
.sidebar {
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
grid-area: sidebar;
|
||||
transition: width 0.2s;
|
||||
background-color: lightgrey;
|
||||
/* background-color: lightgrey; */
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@ -135,7 +192,7 @@
|
||||
}
|
||||
|
||||
@media (min-width: 45rem) {
|
||||
.container {
|
||||
.app-container {
|
||||
grid-template-columns: auto 1fr;
|
||||
}
|
||||
|
||||
@ -163,45 +220,35 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class:loading class="root">
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
{#if sidebar_button}
|
||||
<button on:click={() => (sidebar_active = !sidebar_active)}>
|
||||
<svg
|
||||
id="Layer_1"
|
||||
style="enable-background:new 0 0 32 32;"
|
||||
version="1.1"
|
||||
viewBox="0 0 32 32"
|
||||
width="32px"
|
||||
xml:space="preserve"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<path
|
||||
d="M4,10h24c1.104,0,2-0.896,2-2s-0.896-2-2-2H4C2.896,6,2,6.896,2,8S2.896,10,4,10z
|
||||
M28,14H4c-1.104,0-2,0.896-2,2
|
||||
s0.896,2,2,2h24c1.104,0,2-0.896,2-2S29.104,14,28,14z
|
||||
M28,22H4c-1.104,0-2,0.896-2,2s0.896,2,2,2h24c1.104,0,2-0.896,2-2
|
||||
S29.104,22,28,22z" />
|
||||
</svg>
|
||||
<Theme {dark}>
|
||||
<div class:loading class="root">
|
||||
<div class="app-container">
|
||||
<div class="header">
|
||||
{#if sidebar_button}
|
||||
<button on:click={() => (sidebar_active = !sidebar_active)}>
|
||||
<MenuIcon />
|
||||
</button>
|
||||
{/if}
|
||||
<h1>{page.title}</h1>
|
||||
<button on:click={() => (dark = !dark)} class="theme-btn">
|
||||
<DarkthemeIcon />
|
||||
</button>
|
||||
{/if}
|
||||
<h1>{page.title}</h1>
|
||||
</div>
|
||||
<div class="sidebar elv-16" class:sidebar-visible={sidebar_active}>
|
||||
<NavigationBar open={setPage} {pages} active={page} />
|
||||
</div>
|
||||
<div class="content">
|
||||
<svelte:component this={page.component} bind:loading />
|
||||
</div>
|
||||
<div class="footer" />
|
||||
</div>
|
||||
<div class="sidebar" class:sidebar-visible={sidebar_active}>
|
||||
<NavigationBar open={setPage} {pages} active={page} />
|
||||
</div>
|
||||
<div class="content">
|
||||
<svelte:component this={page.component} bind:loading />
|
||||
</div>
|
||||
<div class="footer" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if loading}
|
||||
<div class="loader_container">
|
||||
<div class="loader_box">
|
||||
<div class="loader" />
|
||||
{#if loading}
|
||||
<div class="loader_container">
|
||||
<div class="loader_box">
|
||||
<div class="loader" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</Theme>
|
||||
|
@ -18,12 +18,17 @@
|
||||
/* justify-content: center; */
|
||||
}
|
||||
|
||||
.subcomponent {
|
||||
padding: 0 var(--rel-size);
|
||||
margin: 0;
|
||||
margin-left: calc(var(--rel-size) * 6);
|
||||
}
|
||||
|
||||
.active {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.icon {
|
||||
/* float: left; */
|
||||
width: calc(var(--rel-size) * 3);
|
||||
height: calc(var(--rel-size) * 3);
|
||||
}
|
||||
@ -33,20 +38,56 @@
|
||||
height: calc(var(--rel-size) * 3);
|
||||
}
|
||||
|
||||
.icon > :global(svg) {
|
||||
width: calc(var(--rel-size) * 3);
|
||||
height: calc(var(--rel-size) * 3);
|
||||
}
|
||||
|
||||
.title {
|
||||
/* margin: auto; */
|
||||
margin-left: var(--rel-size);
|
||||
margin-left: calc(var(--rel-size) * 1.5);
|
||||
/* padding-left: var(--rel-size); */
|
||||
/* height: 100%; */
|
||||
}
|
||||
|
||||
.divide {
|
||||
position: relative;
|
||||
margin-top: var(--rel-size);
|
||||
padding-top: var(--rel-size);
|
||||
}
|
||||
|
||||
.divide::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 1px;
|
||||
width: 100%; /* or 100px */
|
||||
transform: scaleX(0.8);
|
||||
border-top: 1px solid var(--on-background);
|
||||
}
|
||||
</style>
|
||||
|
||||
{#each pages as page}
|
||||
<div
|
||||
class={'container' + (page === active ? ' active' : '')}
|
||||
on:click={() => open(page.id)}>
|
||||
<div class="icon">
|
||||
<img alt={page.title} src={page.icon} />
|
||||
<div class:divide={page.divide}>
|
||||
<div
|
||||
class="container"
|
||||
class:active={page === active}
|
||||
on:click={() => open(page.id)}>
|
||||
<div class="icon">
|
||||
{#if typeof page.icon === 'string'}
|
||||
<img alt={page.title} src={page.icon} />
|
||||
{:else}
|
||||
<svelte:component this={page.icon} />
|
||||
{/if}
|
||||
</div>
|
||||
<h3 class="title">{page.title}</h3>
|
||||
</div>
|
||||
<h3 class="title">{page.title}</h3>
|
||||
{#if page.subComponents}
|
||||
{#each page.subComponents as sub}
|
||||
<h3 class="subcomponent">{sub.title}</h3>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
|
114
src/pages/User/Pages/Apps.svelte
Normal file
@ -0,0 +1,114 @@
|
||||
<script lang="typescript">
|
||||
import { onMount } from "svelte";
|
||||
import Box from "./Box.svelte";
|
||||
import BoxItem from "./BoxItem.svelte";
|
||||
export let loading = false;
|
||||
|
||||
let modalState = false;
|
||||
|
||||
onMount(() => {
|
||||
loading = false;
|
||||
});
|
||||
|
||||
function modal(call: string, apiCall?: string) {
|
||||
if (call == "close") {
|
||||
closeModal();
|
||||
}
|
||||
if (call == "open") {
|
||||
openModal();
|
||||
}
|
||||
|
||||
if (apiCall) {
|
||||
console.log(apiCall);
|
||||
}
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
modalState = false;
|
||||
}
|
||||
function openModal() {
|
||||
modalState = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.btn {
|
||||
background-color: var(--primary);
|
||||
margin: auto 0;
|
||||
margin-left: 1rem;
|
||||
font-size: 1rem;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.btn-delete {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.btn-delete > .btn {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<Box>
|
||||
<h1>Authorized Apps</h1>
|
||||
|
||||
<BoxItem name={'Hedgedoc'} value={'https://md.elijas.de'} highlight={false}>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Permission</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jill</td>
|
||||
<td>Smith</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Eve</td>
|
||||
<td>Jackson</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sanna</td>
|
||||
<td>Castillo</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Petra</td>
|
||||
<td>Serrano</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="btn-delete">
|
||||
<button
|
||||
on:click={() => {
|
||||
modal('open');
|
||||
}}
|
||||
class="btn btn-secondary">
|
||||
delete permissions
|
||||
</button>
|
||||
</div>
|
||||
</BoxItem>
|
||||
</Box>
|
||||
|
||||
{#if modalState}
|
||||
<div id="modal1" class="modal">
|
||||
<div class="modal-title">Delte Hedgedocs permissions</div>
|
||||
<div id="modal1_content" class="modal-content">
|
||||
By pressing the "delete" button you will remove all set permissions for
|
||||
"Hedgedocs". This could mean an irreversible loss of all data of this
|
||||
service.
|
||||
</div>
|
||||
|
||||
<div class="modal-action">
|
||||
<button
|
||||
on:click={() => {
|
||||
modal('close');
|
||||
}}
|
||||
class="btn btn-success">Close</button>
|
||||
<button
|
||||
on:click={() => {
|
||||
modal('close', 'delete');
|
||||
}}
|
||||
class="btn btn-error">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
@ -1,36 +1,33 @@
|
||||
<style>
|
||||
.box {
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.30), 0 5px 4px rgba(0, 0, 0, 0.22);
|
||||
padding: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
background-color: white;
|
||||
}
|
||||
.box {
|
||||
border-radius: 4px;
|
||||
padding: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.box> :global(h1) {
|
||||
margin: 0;
|
||||
margin-bottom: 1rem;
|
||||
color: #444444;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
.box > :global(h1) {
|
||||
margin: 0;
|
||||
margin-bottom: 1rem;
|
||||
/* color: #444444; */
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.box> :global(div) {
|
||||
padding: 16px;
|
||||
border-top: 1px solid var(--border-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.box > :global(div) {
|
||||
border-top: 1px solid var(--border-color);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.box> :global(div):first-of-type {
|
||||
border-top: none;
|
||||
}
|
||||
.box > :global(div):first-of-type {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
@media (min-width: 45rem) {
|
||||
.box {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
}
|
||||
@media (min-width: 45rem) {
|
||||
.box {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="box">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div class="box elv-4">
|
||||
<slot />
|
||||
</div>
|
||||
|
@ -12,12 +12,13 @@
|
||||
|
||||
<style>
|
||||
.root:hover {
|
||||
background-color: rgba(0, 0, 0, 0.04);
|
||||
background-color: rgba(128, 128, 128, 0.1);
|
||||
}
|
||||
|
||||
.container {
|
||||
.boxitem-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.values {
|
||||
@ -34,20 +35,22 @@
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.values > div:nth-child(2) {
|
||||
/* .values > div:nth-child(2) {
|
||||
color: black;
|
||||
}
|
||||
} */
|
||||
|
||||
:global(svg) {
|
||||
:global(.next-icon) {
|
||||
margin: auto 8px auto 8px;
|
||||
height: var(--default-font-size);
|
||||
min-width: var(--default-font-size);
|
||||
fill: var(--on-background);
|
||||
}
|
||||
|
||||
.body {
|
||||
box-sizing: border-box;
|
||||
padding: 0.1px;
|
||||
margin-top: 2rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 45rem) {
|
||||
@ -63,27 +66,31 @@
|
||||
}
|
||||
|
||||
.highlight-element {
|
||||
background-color: #7bff003b;
|
||||
background-color: var(--success);
|
||||
/* #7bff003b */
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="root" class:highlight-element={highlight}>
|
||||
<div class="container" on:click={() => (open = !open)}>
|
||||
<div class="root">
|
||||
<div
|
||||
class="boxitem-container"
|
||||
on:click={() => (open = !open)}
|
||||
class:highlight-element={highlight}>
|
||||
<div class="values">
|
||||
<div>{name}</div>
|
||||
<div>
|
||||
{#if Array.isArray(value)}
|
||||
{#each value as v, i}
|
||||
{v}
|
||||
{#if i < value.length - 1}
|
||||
<br />
|
||||
{/if}
|
||||
{/each}
|
||||
{:else}{value}{/if}
|
||||
<slot name="value">
|
||||
{#if Array.isArray(value)}
|
||||
{#each value as v, i}
|
||||
{v}
|
||||
{#if i < value.length - 1}<br />{/if}
|
||||
{/each}
|
||||
{:else}{value}{/if}
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
{#if !noOpen}
|
||||
<NextIcon rotation={open ? -90 : 90} />
|
||||
<NextIcon class="next-icon" rotation={open ? -90 : 90} />
|
||||
{/if}
|
||||
</div>
|
||||
{#if open && !noOpen}
|
||||
|
46
src/pages/User/Pages/Home.svelte
Normal file
@ -0,0 +1,46 @@
|
||||
<script lang="typescript">
|
||||
import { onMount } from "svelte";
|
||||
import Box from "./Box.svelte";
|
||||
import BoxItem from "./BoxItem.svelte";
|
||||
import { getFeatured, getName } from "../api";
|
||||
export let loading = false;
|
||||
|
||||
const featured = getFeatured();
|
||||
|
||||
let name = "LOADING...";
|
||||
onMount(() => {
|
||||
loading = true;
|
||||
getName().then((n) => {
|
||||
loading = false;
|
||||
name = n;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
a {
|
||||
color: var(--on-surface);
|
||||
}
|
||||
</style>
|
||||
|
||||
<Box>
|
||||
<h1>{name}</h1>
|
||||
<p>
|
||||
{name}
|
||||
is a
|
||||
<a href="/user">OAuth2.0</a>
|
||||
Service powered by
|
||||
<a href="/user">OpenAuth</a>. It's goal is to bundle multiple services
|
||||
logins under one central address.
|
||||
</p>
|
||||
<p>Services currently featured by {name}:</p>
|
||||
|
||||
{#await featured then clients}
|
||||
{#each clients as client}
|
||||
<BoxItem name={client.name} value={client.website} highlight={false}>
|
||||
<a slot="value" href={client.website}>{client.website}</a>
|
||||
<p>{client.description}</p>
|
||||
</BoxItem>
|
||||
{/each}
|
||||
{/await}
|
||||
</Box>
|
@ -1,13 +1,22 @@
|
||||
<script>
|
||||
export let rotation;
|
||||
export let rotation;
|
||||
</script>
|
||||
|
||||
<svg style={`enable-background:new 0 0 35.414 35.414; transform: rotate(${rotation}deg); transition: all .4s;`}
|
||||
version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||
y="0px" viewBox="0 0 35.414 35.414" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<polygon points="27.051,17 9.905,0 8.417,1.414 24.674,17.707 8.363,34 9.914,35.414 27.051,18.414 " />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
<svg
|
||||
{...$$props}
|
||||
style={`enable-background:new 0 0 35.414 35.414; transform: rotate(${rotation}deg); transition: all .4s;`}
|
||||
version="1.1"
|
||||
id="Capa_1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 35.414 35.414"
|
||||
xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<polygon
|
||||
points="27.051,17 9.905,0 8.417,1.414 24.674,17.707 8.363,34 9.914,35.414 27.051,18.414 " />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
@ -170,7 +170,7 @@
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<h1>Anmeldungen</h1>
|
||||
<h1>Logins</h1>
|
||||
|
||||
{#each token as t}
|
||||
<BoxItem name={t.browser} value={t.ip} highlight={t.isthis}>
|
||||
|
0
src/pages/User/Pages/admin/Admin.svelte
Normal file
33
src/pages/User/api.ts
Normal file
@ -0,0 +1,33 @@
|
||||
export async function isAdmin() {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
export async function getName() {
|
||||
if (cache.has("name")) {
|
||||
return cache.get("name");
|
||||
} else {
|
||||
const { name } = await fetch("/api/config.json").then((res) =>
|
||||
res.json()
|
||||
);
|
||||
|
||||
cache.set("name", name);
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
const cache = new Map<string, any>();
|
||||
|
||||
export async function getFeatured() {
|
||||
if (cache.has("featured")) {
|
||||
return cache.get("featured");
|
||||
} else {
|
||||
const { clients } = await fetch("/api/client/featured").then((res) =>
|
||||
res.json()
|
||||
);
|
||||
|
||||
cache.set("featured", clients);
|
||||
|
||||
return clients;
|
||||
}
|
||||
}
|