first commit

This commit is contained in:
Philipp 2024-04-23 18:38:06 +02:00
commit 1a4cbad65a
Signed by: Spaenny
GPG Key ID: 9EBD8439AFBAB750
18 changed files with 382 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

1
.npmrc Normal file
View File

@ -0,0 +1 @@
engine-strict=true

38
README.md Normal file
View File

@ -0,0 +1,38 @@
# create-svelte
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
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://kit.svelte.dev/docs/adapters) for your target environment.

BIN
bun.lockb Executable file

Binary file not shown.

25
package.json Normal file
View File

@ -0,0 +1,25 @@
{
"name": "polls-svelte",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"autoprefixer": "^10.4.18",
"postcss": "^8.4.35",
"svelte": "^4.2.7",
"tailwindcss": "^3.4.1",
"vite": "^5.1.6"
},
"type": "module",
"dependencies": {
"matrix-js-sdk": "^31.4.0",
"svelte-use-form": "latest"
}
}

6
postcss.config.js Normal file
View File

@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

3
src/app.css Normal file
View File

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

12
src/app.html Normal file
View File

@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

1
src/lib/index.js Normal file
View File

@ -0,0 +1 @@
// place files you want to import through the `$lib` alias in this folder.

13
src/routes/+layout.svelte Normal file
View File

@ -0,0 +1,13 @@
<script>
import "../app.css";
export const load = async ({ request, locals, cookies }) => {
return {
user: locals.user
};
};
</script>
<slot />

View File

@ -0,0 +1,26 @@
import { fail, redirect } from '@sveltejs/kit';
export const actions = {
default: async ({ request, cookies }) => {
//if (cookies.get('matrixToken')) {
// redirect(302, '/emotes');
//}
const data = await request.formData();
const homeserver = data.get('url');
const username = data.get('username');
const password = data.get('password');
let token = "";
if(!homeserver || !username || !password ) return fail(400, "Invalid credentials");
cookies.set(
'matrixToken', token, {
path: '/',
maxAge: 60 * 60 * 24 * 365,
httpOnly: false
},
);
redirect(302, '/');
}
}

61
src/routes/+page.svelte Normal file
View File

@ -0,0 +1,61 @@
<script>
import { enhance } from '$app/forms';
export let data;
let homeserver, username, password = "";
let result = null;
async function matrixLogin() {
const res = await fetch(homeserver + "/_matrix/client/r0/login", {
method: "POST",
body: JSON.stringify({
"type": "m.login.password",
"user": username,
"password": password
})
});
const json = await res.json();
result = json;
if(result) data.matrixToken = result.access_token
}
</script>
<section class="bg-gray-50 dark:bg-gray-900">
<div class="flex flex-col items-center justify-center px-6 py-8 mx-auto md:h-screen lg:py-0">
<a href="/" class="flex items-center mb-6 text-2xl font-semibold text-gray-900 dark:text-white">
<img class="w-8 h-8 mr-2" src="https://flowbite.s3.amazonaws.com/blocks/marketing-ui/logo.svg" alt="logo">
Emote Matrix
</a>
<div class="w-full bg-white rounded-lg shadow dark:border md:mt-0 sm:max-w-md xl:p-0 dark:bg-gray-800 dark:border-gray-700">
<div class="p-6 space-y-4 md:space-y-6 sm:p-8">
<h1 class="text-xl font-bold leading-tight tracking-tight text-gray-900 md:text-2xl dark:text-white">
Sign in to your Matrix Account
</h1>
<form method="POST" class="space-y-4 md:space-y-3" use:enhance>
<div>
<label for="url" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Homeserver</label>
<input bind:value={homeserver} type="url" name="url" id="url" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="https://matrix.boehm.sh"/>
</div>
<div>
<label for="username" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Username</label>
<input bind:value={username} type="username" name="username" id="username" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="Username"/>
</div>
<div>
<label for="password" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Password</label>
<input bind:value={password} type="password" name="password" id="password" placeholder="••••••••" class="bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" />
</div>
<div class="mt-5">
<button on:click={matrixLogin} type="submit" class="w-full text-white bg-primary-600 hover:bg-primary-700 focus:ring-4 focus:outline-none focus:ring-primary-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">Sign in</button>
</div>
</form>
</div>
</div>
</div>
</section>
<style lang="postcss">
:global(.touched.invalid) {
broder-color: red;
outline-color: red;
}
</style>

View File

@ -0,0 +1,118 @@
<script>
import {flip} from 'svelte/animate';
import { onMount } from 'svelte';
let baskets = [];
let isLoading = true;
onMount(async () => {
const response = await fetch("https://matrix.org/_matrix/client/v3/rooms/!WesIJpYbWDvdAYThkW:matrix.org/state", {
method: "GET",
headers: {
"Authorization": "Bearer xxx"
}
})
const data = await response.json();
data.forEach(e => {
if(e.type === "im.ponies.room_emotes" && e.content.pack != undefined) {
let prepareArr = [];
for(const [key, value] of Object.entries(e.content.images)) {
let image_id = value.url.split("/")[3];
let hs = value.url.split("/")[2];
prepareArr.push("https://matrix.boehm.sh/_matrix/media/r0/thumbnail/" + hs + "/" + image_id + "?width=256&height=256&method=crop")
}
baskets.push({"name": e.content.pack.display_name, "items": prepareArr})
}
});
isLoading = false;
});
let hoveringOverBasket;
function dragStart(event, basketIndex, itemIndex) {
// The data we want to make available when the element is dropped
// is the index of the item being dragged and
// the index of the basket from which it is leaving.
const data = {basketIndex, itemIndex};
event.dataTransfer.setData('text/plain', JSON.stringify(data));
}
function drop(event, basketIndex) {
event.preventDefault();
const json = event.dataTransfer.getData("text/plain");
const data = JSON.parse(json);
// Remove the item from one basket.
// Splice returns an array of the deleted elements, just one in this case.
const [item] = baskets[data.basketIndex].items.splice(data.itemIndex, 1);
// Add the item to the drop target basket.
baskets[basketIndex].items.push(item);
baskets = baskets;
hoveringOverBasket = null;
}
</script>
{#if isLoading}
<p>Loading the Emotes...</p>
{:else}
{#each baskets as basket, basketIndex (basket)}
<div animate:flip>
<b>{basket.name}</b>
<ul
class:hovering={hoveringOverBasket === basket.name}
on:dragenter={() => hoveringOverBasket = basket.name}
on:dragleave={() => hoveringOverBasket = null}
on:drop={event => drop(event, basketIndex)}
ondragover="return false" >
{#each basket.items as item, itemIndex (item)}
<div class="item" animate:flip>
<li
draggable={true}
on:dragstart={event => dragStart(event, basketIndex, itemIndex)} >
<img src={item} alt="Emote"/>
</li>
</div>
{/each}
</ul>
</div>
{/each}
{/if}
<style>
.hovering {
border-color: orange;
}
.item {
display: inline; /* required for flip to work */
}
li {
background-color: lightgray;
cursor: pointer;
display: inline-block;
margin-right: 10px;
margin-top: 10px;
padding: 10px;
}
li:hover {
background: orange;
color: white;
}
ul {
border: solid lightgray 1px;
display: fit-content; /* required for drag & drop to work when .item display is inline */
padding: 10px;
margin-left: 10px;
width: 100%;
min-height: 100px;
table-layout: fixed;
}
b {
margin-left: 10px;
}
p {
margin-left: 10px;
}
img {
height: 32px;
}
</style>

34
src/routes/hook.server.js Normal file
View File

@ -0,0 +1,34 @@
import { userRepository } from './lib/Redis/dbRepository';
function redirect(location, body) {
return new Response(body, {
status: 303,
headers: { location }
});
}
const unProtectedRoutes = [
'/'
];
export const handle= async ({ event, resolve }) => {
const session = event.cookies.get('session');
if (!session && !unProtectedRoutes.includes(event.url.pathname))
return redirect('/login', 'No authenticated user.');
const currentUser = await userRepository.fetch(session);
if (currentUser) {
event.locals.user = {
isAuthenticated: true,
name: currentUser.name,
email: currentUser.email,
type: currentUser.user_type,
active: currentUser.active,
phone: currentUser.phone
};
} else {
if (!unProtectedRoutes.includes(event.url.pathname)) return redirect('/', 'Not a valid user');
}
return resolve(event);
};

BIN
static/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

15
svelte.config.js Normal file
View File

@ -0,0 +1,15 @@
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter()
},
preprocess: vitePreprocess()
};
export default config;

13
tailwind.config.js Normal file
View File

@ -0,0 +1,13 @@
/** @type {import('tailwindcss').Config} */
export default {
content: ["./src/**/*.{html,js,svelte,ts}"],
theme: {
extend: {
colors: {
primary: {"50":"#eff6ff","100":"#dbeafe","200":"#bfdbfe","300":"#93c5fd","400":"#60a5fa","500":"#3b82f6","600":"#2563eb","700":"#1d4ed8","800":"#1e40af","900":"#1e3a8a","950":"#172554"}
}
},
},
plugins: [],
}

6
vite.config.js Normal file
View File

@ -0,0 +1,6 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()]
});