Compare commits

..

14 commits

12 changed files with 147 additions and 105 deletions

View file

@ -1,38 +1,21 @@
# sv # Jonas_Jones Dashboard
This Dashboard connects the settings and configurations of most of the services of my ecosystem
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli). ## Accounts
It is possible for everyone to signup and get access to the settings, however most user scopes aren't available to the default user and need to be granted by an admin user.
## Creating a project ## Settings and Configurations
The following are services that can be configured from the dashboard:
If you're seeing this, you've probably already done this step. Congrats! | Service Name | Description | Implemented |
| ------------ | ----------- | ----------- |
```bash | accouts.jonasjones.dev | Account Management (scopes, deletion, creation, etc...) | No |
# create a new project in the current directory | jonasjones.dev (Projects) | Project Management (update, add, delete) | No |
npx sv create | Analytics (stats.jonasjones.dev) | Management (delete, graphs) | No |
| Rick-Roll-Tracker | Management (graphs) | No |
# create a new project in my-app | kcomebacks.jonasjones.dev | run scraper, graphs, etc... | No |
npx sv create my-app | builds.jonasjones.dev | Add, remove, update | No |
``` | blogs.jonasjones.dev | create, edit, delete Posts | No |
| rss.jonasjones.dev | add, edit, delete entries | No |
## Developing | API scripts | run, (probably not much more because security issues like remote code execution etc.) | No |
| aka.jonasjones.dev | add, remove, edit aka entries | No |
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
To create a production version of your app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.

View file

@ -0,0 +1,32 @@
<div class="alpha-notice">
<h2><b>This is an Alpha Version</b></h2>
<p>
Note that this Dashboard is in an alpha state. This means that there are bugs and missing features.
Please report any bugs or issues to the
<a href="https://github.com/JonasunderscoreJones/dash.jonasjones.dev/issues">GitHub repository</a>.
</p>
</div>
<style>
.alpha-notice {
background-color: #c48900;
color: #721c24;
padding: 1rem;
border: 1px solid #533300;
border-radius: 0.25rem;
margin: 1rem 0;
}
.alpha-notice h2 {
margin-top: 0;
}
.alpha-notice a {
color: #721c24;
text-decoration: underline;
}
.alpha-notice a:hover {
color: #560009;
}
</style>

View file

@ -1,3 +1,5 @@
export const ACCOUNTS_WORKER_URL = 'https://accounts.jonasjones.dev';
export function getSessionKey() { export function getSessionKey() {
const match = document.cookie.match(/(^| )sessionKey=([^;]+)/); const match = document.cookie.match(/(^| )sessionKey=([^;]+)/);
return match ? match[2] : null; return match ? match[2] : null;
@ -12,6 +14,20 @@ export function redirectToLogin() {
window.location.href = `/login?returnUrl=${currentPath}`; window.location.href = `/login?returnUrl=${currentPath}`;
} }
export function resetSession() {
document.cookie = `sessionKey=; path=/; max-age=0`;
window.location.href = '/login';
}
export function redirectToHome() {
if (getSessionKey()) {
window.location.href = new URLSearchParams(window.location.search).get('returnUrl') || '/';
console.log(new URLSearchParams(window.location.search).get('returnUrl') || '/')
} else {
console.log(getSessionKey())
}
}
export function ensureAuthenticated() { export function ensureAuthenticated() {
if (!getSessionKey()) { if (!getSessionKey()) {
redirectToLogin(); redirectToLogin();

View file

@ -6,6 +6,11 @@
let { children } = $props(); let { children } = $props();
</script> </script>
<head>
<!-- Include Font Awesome CDN -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
</head>
<div class="app"> <div class="app">
<Header /> <Header />
@ -22,33 +27,4 @@
flex-direction: column; flex-direction: column;
min-height: 100vh; min-height: 100vh;
} }
main {
flex: 1;
display: flex;
flex-direction: column;
padding: 1rem;
width: 100%;
max-width: 64rem;
margin: 0 auto;
box-sizing: border-box;
}
footer {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 12px;
}
footer a {
font-weight: bold;
}
@media (min-width: 480px) {
footer {
padding: 12px 0;
}
}
</style> </style>

View file

@ -1,7 +1,6 @@
<script> <script>
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { ensureAuthenticated } from '../utils/session.js'; import { ensureAuthenticated } from '$lib/session.js';
onMount(() => { onMount(() => {
ensureAuthenticated(); // This will check the session key and redirect if necessary ensureAuthenticated(); // This will check the session key and redirect if necessary
}); });

View file

@ -1,14 +1,9 @@
<head>
<!-- Include Font Awesome CDN -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet">
</head>
<div class="footer"> <div class="footer">
<div class="footer-left"> <div class="footer-left">
<a href="https://github.com/JonasunderscoreJones" target="_blank"><i class="fab fa-github" /></a> <a href="https://github.com/JonasunderscoreJones" target="_blank" aria-label="GitHub Link"><i class="fab fa-github"></i></a>
<a href="https://www.youtube.com/channel/UCVIxvKBIMSMgurYS8pK7fSg" target="_blank"><i class="fab fa-youtube" /></a> <a href="https://www.youtube.com/channel/UCVIxvKBIMSMgurYS8pK7fSg" target="_blank" aria-label="YouTube Link"><i class="fab fa-youtube"></i></a>
<a href="https://discord.gg/V2EsuUVmWh" target="_blank"><i class="fab fa-discord" /></a> <a href="https://discord.gg/V2EsuUVmWh" target="_blank" aria-label="Discord Link"><i class="fab fa-discord"></i></a>
<a href="mailto:me@jonasjones.dev" target="_blank"><i class="fas fa-envelope" /></a> <a href="mailto:me@jonasjones.dev" target="_blank" aria-label="Email Link"><i class="fas fa-envelope"></i></a>
</div> </div>
<p>Website by Jonas_Jones 2021 - <script>document.write(new Date().getFullYear());</script></p> <p>Website by Jonas_Jones 2021 - <script>document.write(new Date().getFullYear());</script></p>

View file

@ -1,6 +1,13 @@
<script> <script>
import { page } from '$app/state'; import { page } from '$app/state';
import logo from '$lib/images/logo.png'; import logo from '$lib/images/logo.png';
import { getSessionKey } from '$lib/session.js';
import { onMount } from 'svelte';
let sessionKey;
onMount(() => {
sessionKey = getSessionKey();
});
</script> </script>
<header> <header>
@ -15,13 +22,16 @@
<path d="M0,0 L1,2 C1.5,3 1.5,3 2,3 L2,0 Z" /> <path d="M0,0 L1,2 C1.5,3 1.5,3 2,3 L2,0 Z" />
</svg> </svg>
<ul> <ul>
{#if ['/login', '/signup', '/register'].includes(page.url.pathname)} {#if sessionKey === null}
<li aria-current={page.url.pathname === '/login' ? 'page' : undefined}> <li aria-current={page.url.pathname === '/login' ? 'page' : undefined}>
<a href="/login{page.url.search}">Login</a> <a href="/login{page.url.search}">Login</a>
</li> </li>
<li aria-current={page.url.pathname === '/signup' ? 'page' : undefined}> <li aria-current={page.url.pathname === '/signup' ? 'page' : undefined}>
<a href="/signup{page.url.search}">Signup</a> <a href="/signup{page.url.search}">Signup</a>
</li> </li>
<li aria-current={page.url.pathname === '/about' ? 'page' : undefined}>
<a href="/about">About</a>
</li>
{:else} {:else}
<li aria-current={page.url.pathname === '/' ? 'page' : undefined}> <li aria-current={page.url.pathname === '/' ? 'page' : undefined}>
<a href="/">Home</a> <a href="/">Home</a>
@ -29,6 +39,9 @@
<li aria-current={page.url.pathname === '/about' ? 'page' : undefined}> <li aria-current={page.url.pathname === '/about' ? 'page' : undefined}>
<a href="/about">About</a> <a href="/about">About</a>
</li> </li>
<li aria-current={page.url.pathname === '/logout' ? 'page' : undefined}>
<a href="/logout">Logout</a>
</li>
{/if} {/if}
</ul> </ul>
<svg viewBox="0 0 2 3" aria-hidden="true"> <svg viewBox="0 0 2 3" aria-hidden="true">

View file

@ -1,9 +0,0 @@
import { dev } from '$app/environment';
// we don't need any JS on this page, though we'll load
// it in dev so that we get hot module replacement
export const csr = dev;
// since there's no dynamic data here, we can prerender
// it so that it gets served as a static asset in production
export const prerender = true;

View file

@ -1,21 +1,37 @@
<script>
import AlphaNotice from "$lib/components/AlphaNotice.svelte";
</script>
<svelte:head> <svelte:head>
<title>About</title> <title>About</title>
<meta name="description" content="About this app" /> <meta name="description" content="About this app" />
</svelte:head> </svelte:head>
<div class="text-column"> <div class="text-column">
<h1>About this app</h1> <h1>About this Dashboard</h1>
<AlphaNotice />
<p> <p>
This is a <a href="https://svelte.dev/docs/kit">SvelteKit</a> app. You can make your own by typing This is a Dashboard app for my Ecosystem's services.
the following into your command line and following the prompts: The list and roadmap of supported services can be viewed in the
<a href="https://github.com/JonasunderscoreJones/dash.jonasjones.dev/blob/main/README.md">README.md</a>
page of the github repository. Thus, the Dashboard is opensource in the same repository.
</p> </p>
<pre>npx sv create</pre> <p>
Signups are allowed to anyone. This is because the default user scope currently has no permissions.
However, the Dashboard is designed to be used with a user scope system. This means that the user scope
will be able to access services that are only available to them. Scopes are granted by an admin account.
</p>
<p> <p>
The page you're looking at is purely static HTML, with no client-side interactivity needed. Further are the accounts not limited to the Dashboard. They are their own entity, hosted on cloudflare workers.
Because of that, we don't need to load any JavaScript. Try viewing the page's source, or opening Thus, the accounts are available to be used in other projects as well. The accounts are also opensource in the
the devtools network panel and reloading. <a href="https://github.com/JonasunderscoreJones/accounts.jonasjones.dev/">github repository</a>.
</p>
<p>
Tldr; Dashboard is opensource and signup is public but has no permissions, unless explicitly granted by an admin.
</p> </p>
</div> </div>

View file

@ -1,15 +1,21 @@
<script> <script>
import { navigate } from 'svelte-routing'; import { navigate } from 'svelte-routing';
import { setSessionKey } from '../../utils/session.js'; import { onMount } from 'svelte';
import { setSessionKey, redirectToHome, ACCOUNTS_WORKER_URL } from '$lib/session.js';
import { page } from '$app/state'; import { page } from '$app/state';
import AlphaNotice from '$lib/components/AlphaNotice.svelte';
let email = ''; let email = '';
let password = ''; let password = '';
let errorMessage = ''; let errorMessage = '';
let showPassword = false; let showPassword = false;
onMount(() => {
redirectToHome(); // This will check the session key and redirect if necessary
});
const handleLogin = async () => { const handleLogin = async () => {
try { try {
const response = await fetch('https://accounts.jonasjones.dev/login', { const response = await fetch(ACCOUNTS_WORKER_URL + '/login', {
method: 'POST', method: 'POST',
body: JSON.stringify({ email, password }), body: JSON.stringify({ email, password }),
headers: { headers: {
@ -38,6 +44,8 @@
<div class="login-prompt"> <div class="login-prompt">
<h1>Login</h1> <h1>Login</h1>
<AlphaNotice />
{#if errorMessage} {#if errorMessage}
<p style="color: red;">{errorMessage}</p> <p style="color: red;">{errorMessage}</p>
{/if} {/if}
@ -73,12 +81,11 @@
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
position: fixed; position: relative;
top: 50px;
left: 0;
align-items: center; align-items: center;
height: 100vh; height: 80vh;
width: 100vw; width: 100vw;
margin-top: 25px;
} }
.login-prompt { .login-prompt {

View file

@ -0,0 +1,12 @@
<script>
import { goto } from '$app/navigation';
import { resetSession } from '$lib/session.js';
resetSession();
goto('/login');
</script>
<div>
<h1>Logging out...</h1>
<p>Redirecting to the login page...</p>
</div>

View file

@ -1,7 +1,8 @@
<script> <script>
import { navigate } from 'svelte-routing'; import { navigate } from 'svelte-routing';
import { setSessionKey } from '../../utils/session.js'; import { setSessionKey, ACCOUNTS_WORKER_URL } from '$lib/session.js';
import { page } from '$app/state'; import { page } from '$app/state';
import AlphaNotice from '$lib/components/AlphaNotice.svelte';
let username = ''; let username = '';
let firstname = ''; let firstname = '';
let lastname = ''; let lastname = '';
@ -12,7 +13,7 @@
const handleLogin = async () => { const handleLogin = async () => {
try { try {
const response = await fetch('https://accounts.jonasjones.dev/register', { const response = await fetch(ACCOUNTS_WORKER_URL + '/register', {
method: 'POST', method: 'POST',
body: JSON.stringify({ email, password, username, firstname, lastname }), body: JSON.stringify({ email, password, username, firstname, lastname }),
headers: { headers: {
@ -41,6 +42,8 @@
<div class="login-prompt"> <div class="login-prompt">
<h1>Signup</h1> <h1>Signup</h1>
<AlphaNotice />
{#if errorMessage} {#if errorMessage}
<p style="color: red;">{errorMessage}</p> <p style="color: red;">{errorMessage}</p>
{/if} {/if}
@ -83,12 +86,11 @@
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
position: fixed; position: relative;
top: 50px;
left: 0;
align-items: center; align-items: center;
height: 100vh; height: 80vh;
width: 100vw; width: 100vw;
margin-top: 25px;
} }
.login-prompt { .login-prompt {
@ -141,7 +143,7 @@
} }
button:hover { button:hover {
background-color: #0056b3; background-color: var(--color-theme-2);
} }
p { p {