mirror of
https://github.com/JonasunderscoreJones/dash.jonasjones.dev.git
synced 2025-10-25 14:29:18 +02:00
Compare commits
14 commits
a4e42be994
...
53eeebaf0a
| Author | SHA1 | Date | |
|---|---|---|---|
| 53eeebaf0a | |||
| 9877879ba6 | |||
| 236777e7f3 | |||
| f75c99a571 | |||
| 6dcce58635 | |||
| d1d25ee292 | |||
| 31ad9c36d6 | |||
| 218d53fb92 | |||
| 01da5efe2f | |||
| f0eedba287 | |||
| e5c9c351e7 | |||
| 10cc36000c | |||
| e032477540 | |||
| 9a2d157d37 |
12 changed files with 147 additions and 105 deletions
53
README.md
53
README.md
|
|
@ -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.
|
|
||||||
|
|
|
||||||
32
src/lib/components/AlphaNotice.svelte
Normal file
32
src/lib/components/AlphaNotice.svelte
Normal 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>
|
||||||
|
|
@ -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();
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
12
src/routes/logout/+page.svelte
Normal file
12
src/routes/logout/+page.svelte
Normal 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>
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue