Making everything nicer #2
							
								
								
									
										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,9 +15,14 @@
 | 
			
		||||
  li > a {
 | 
			
		||||
    text-decoration: none;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  :root {
 | 
			
		||||
    --primary: yellow;
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<div class="main">
 | 
			
		||||
<Theme dark={true}>
 | 
			
		||||
  <div class="main">
 | 
			
		||||
    <h1>Home Page</h1>
 | 
			
		||||
 | 
			
		||||
    <h2>About</h2>
 | 
			
		||||
@ -24,21 +33,17 @@
 | 
			
		||||
    </p>
 | 
			
		||||
 | 
			
		||||
    <h2>QickLinks</h2>
 | 
			
		||||
  <p>
 | 
			
		||||
    If you want to manage your Account, click
 | 
			
		||||
    <a href="user.html">here</a>
 | 
			
		||||
  </p>
 | 
			
		||||
    <p>If you want to manage your Account, click <a href="/user">here</a></p>
 | 
			
		||||
 | 
			
		||||
    <h2>Applications using OpenAuth</h2>
 | 
			
		||||
 | 
			
		||||
    <ul>
 | 
			
		||||
    <li>
 | 
			
		||||
      <a href="https://ebook.stamm.me">EBook Store and Reader</a>
 | 
			
		||||
    </li>
 | 
			
		||||
      <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>
 | 
			
		||||
  </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,32 +220,21 @@
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<div class:loading class="root">
 | 
			
		||||
  <div class="container">
 | 
			
		||||
<Theme {dark}>
 | 
			
		||||
  <div class:loading class="root">
 | 
			
		||||
    <div class="app-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>
 | 
			
		||||
            <MenuIcon />
 | 
			
		||||
          </button>
 | 
			
		||||
        {/if}
 | 
			
		||||
        <h1>{page.title}</h1>
 | 
			
		||||
        <button on:click={() => (dark = !dark)} class="theme-btn">
 | 
			
		||||
          <DarkthemeIcon />
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
    <div class="sidebar" class:sidebar-visible={sidebar_active}>
 | 
			
		||||
      <div class="sidebar elv-16" class:sidebar-visible={sidebar_active}>
 | 
			
		||||
        <NavigationBar open={setPage} {pages} active={page} />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="content">
 | 
			
		||||
@ -196,12 +242,13 @@
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="footer" />
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
{#if loading}
 | 
			
		||||
  {#if loading}
 | 
			
		||||
    <div class="loader_container">
 | 
			
		||||
      <div class="loader_box">
 | 
			
		||||
        <div class="loader" />
 | 
			
		||||
      </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:divide={page.divide}>
 | 
			
		||||
    <div
 | 
			
		||||
    class={'container' + (page === active ? ' active' : '')}
 | 
			
		||||
      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>
 | 
			
		||||
    {#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,26 +1,23 @@
 | 
			
		||||
<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> :global(h1) {
 | 
			
		||||
  .box > :global(h1) {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    margin-bottom: 1rem;
 | 
			
		||||
      color: #444444;
 | 
			
		||||
    /* color: #444444; */
 | 
			
		||||
    font-size: 1.3rem;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
   .box> :global(div) {
 | 
			
		||||
      padding: 16px;
 | 
			
		||||
  .box > :global(div) {
 | 
			
		||||
    border-top: 1px solid var(--border-color);
 | 
			
		||||
    word-wrap: break-word;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
   .box> :global(div):first-of-type {
 | 
			
		||||
  .box > :global(div):first-of-type {
 | 
			
		||||
    border-top: none;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -31,6 +28,6 @@
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<div class="box">
 | 
			
		||||
   <slot></slot>
 | 
			
		||||
<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>
 | 
			
		||||
        <slot name="value">
 | 
			
		||||
          {#if Array.isArray(value)}
 | 
			
		||||
            {#each value as v, i}
 | 
			
		||||
              {v}
 | 
			
		||||
            {#if i < value.length - 1}
 | 
			
		||||
              <br />
 | 
			
		||||
            {/if}
 | 
			
		||||
              {#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>
 | 
			
		||||
@ -2,12 +2,21 @@
 | 
			
		||||
  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">
 | 
			
		||||
<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 		" />
 | 
			
		||||
      <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;
 | 
			
		||||
   }
 | 
			
		||||
}
 | 
			
		||||