27 Commits

Author SHA1 Message Date
deno-deploy[bot]
4fb87cc127 [Deno Deploy] Update .github/workflows/deploy.yml 2025-04-04 06:50:43 +00:00
deno-deploy[bot]
def0f2bd9c [Deno Deploy] Add .github/workflows/deploy.yml 2025-04-04 06:40:33 +00:00
Lynixenn
68aa7c20f3 removed files 2025-03-30 21:57:57 +02:00
Lynixenn
6e87e5003e Utils added extra 2025-03-30 21:57:15 +02:00
Esad Mustafoski
0ecd265ade Update deno.json
Quick fix
2025-03-29 00:36:11 +01:00
Lynixenn
895a40fe67 Added database creation upon start of API, only does this when the Database doesn't exist. 2025-03-28 23:51:03 +01:00
Lynixenn
cfcfd4ba5e Fixed Login and Register user not returning, Fixed error upon logging/registering 2025-03-25 18:41:39 +01:00
Lynixenn
9e7039c72c Now returns userId upon Register 2025-03-24 21:21:45 +01:00
Esad Mustafoski
029fc10de7 Fix Error in create_db 2025-03-21 08:32:28 +01:00
Esad Mustafoski
8b594990ee Update create_db.ts 2025-03-20 11:56:23 +01:00
Esad Mustafoski
65ced2f3d3 Update helpers.ts to match comment structure 2025-03-18 08:31:14 +01:00
Esad Mustafoski
497d5aa28f Generated API Docs using AI, Might edit later if there is an issue or it's hard to read. Finished API Functions 2025-03-17 21:39:26 +01:00
Esad Mustafoski
8b992017ba Modulized the project so it's easier to look over items, Unfinished for now, added extra functions for chat, API is not finished for the chat. and will not work. Files saved as a "Work in progress" type of commit. \n Document folders added, but nothing yet done inside of them. \n Some comments have been removed as they were bloated and made it hard to read the code, the functions themselves are self-explanatory and will be documented in the "docs" folders, containing the documentation in a markdown format 2025-03-14 06:37:08 +01:00
Esad Mustafoski
aeaae9fc58 Huge changes! Added some API features, but not fully. 2025-03-14 06:33:12 +01:00
Esad Mustafoski
4c80caa52a Attempted adding of 'Salting' for the password, a method which adds random numbers or letters to make rainbowtable password cracking impossible, not tested yet 2025-02-02 12:33:47 +01:00
Lynixenn
3c6fdd0b59 Fixed account_created format 2024-12-17 22:21:53 +01:00
Lynixenn
4dfa695458 Added body response for Successful login 2024-12-17 19:04:47 +01:00
Lynixenn
010e518828 Login and Register API added, further info shared between Owners 2024-12-17 19:01:14 +01:00
Esad Mustafoski
b0f8a51cc8 Shortened database/utils.ts by adding a 'Query Database' helper function to reduce boilerplate/copied code, also added functions form apping the Post, Account and Comment row. api/main.ts now has more unfinished endpoints and will now work using functions instead of doing everything inside of the routes, created a helpers.ts file to make it a bit more modular and easier to look over. 2024-11-13 23:29:59 +01:00
Esad Mustafoski
7a6152be51 Combined functions, Changed some items 2024-11-07 19:29:35 +01:00
Lynixen
f45945474d Changed functions in database/utils.ts 2024-11-06 21:35:41 +01:00
Esad Mustafoski
064b864246 Removed file 2024-11-06 04:51:35 +01:00
Esad Mustafoski
4d06db689d Removed file 2024-11-06 04:51:09 +01:00
Esad Mustafoski
c786ddd895 Merged some functions in database/utils.ts to attempt to shorten code length, Also changed tests to work with the new datatypes 2024-11-06 04:49:18 +01:00
Esad Mustafoski
108b3f0d50 Updated readme to be more current 2024-11-05 02:32:49 +01:00
Esad Mustafoski
abe39c0797 Documentation Update 2024-11-05 02:22:11 +01:00
Esad Mustafoski
3d31061087 Added API and Tests, Tests generated using AI and will be replaced sometime 2024-11-05 02:05:39 +01:00
57 changed files with 744 additions and 2998 deletions

View File

@@ -1,9 +1,9 @@
name: Deploy
on:
push:
branches: main
branches: api-dev
pull_request:
branches: main
branches: api-dev
jobs:
deploy:
@@ -35,7 +35,7 @@ jobs:
uses: denoland/deployctl@v1
with:
project: "esp-projekt"
entrypoint: "src/main.ts"
entrypoint: "api/main.ts"
root: ""

2
.gitignore vendored
View File

@@ -13,6 +13,8 @@ dist-ssr
.vite
*.local
*.sqlite
*.idea
.env
# Editor directories and files
.vscode/*

View File

@@ -10,22 +10,19 @@ ESP is a simple social media platform built with [Deno](https://deno.land/), [Vi
We're building ESP to avoid the clutter of other Social Media websites.
It's built to be simple, fast and easy to use, all while keeping a Minimal feeling to it.
It's build to be simple, fast and easy to use, all while keeping a Minimal feeling to it.
---
# How do I run it?
The only dependency is Deno! Nothing else is required, Deno will install all the Modules needed and start it.
## Running
API + Website:
Dev server:
```bash
$ deno task dev
```
API only:
```bash
$ deno task dev:api
@@ -49,22 +46,28 @@ $ deno task build
# Resources
## Libs/Frameworks used
<ul>
<li><a href="https://deno.land/"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/84/Deno.svg/600px-Deno.svg.png" width="20" height="20"> Deno</a></li>
<li><a href="https://vitejs.dev/"><img src="https://vitejs.dev/logo.svg" width="20" height="20"> Vite</a></li>
<li><a href="https://www.typescriptlang.org/"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Typescript_logo_2020.svg/512px-Typescript_logo_2020.svg.png?20221110153201" width="20" height="20"> TypeScript</a></li>
<li><a href="https://oakserver.github.io/oak/"><img src="https://oakserver.org/oak_logo.svg?__frsh_c=2e345d91800d1e0a52aa35efcaab769fa1768888" width="20" height="20"> Oak</a></li>
<li><a href="https://www.sqlite.org/"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/38/SQLite370.svg/220px-SQLite370.svg.png" width="20" height="20"> SQLite</a></li>
<li><a href="https://tailwindcss.com/"><img src="https://tailwindcss.com/_next/static/media/tailwindcss-mark.3c5441fc7a190fb1800d4a5c7f07ba4b1345a9c8.svg" width="20" height="20"> TailwindCSS</a></li>
<li><a href="https://vuejs.org/"><img src="https://upload.wikimedia.org/wikipedia/commons/9/95/Vue.js_Logo_2.svg" width="20" height="20">Vue</a></li>
## Frameworks used
<ul>
<li><a href="https://deno.land/"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/84/Deno.svg/600px-Deno.svg.png" width="20" height="20"> Deno</a></li>
<li><a href="https://vitejs.dev/"><img src="https://vitejs.dev/logo.svg" width="20" height="20"> Vite</a></li>
<li><a href="https://www.typescriptlang.org/"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Typescript_logo_2020.svg/512px-Typescript_logo_2020.svg.png?20221110153201" width="20" height="20"> TypeScript</a></li>
<li><a href="https://tailwindcss.com/"><img src="https://tailwindcss.com/_next/static/media/tailwindcss-mark.3c5441fc7a190fb1800d4a5c7f07ba4b1345a9c8.svg" width="20" height="20"> TailwindCSS</a></li>
<li><a href="https://vuejs.org/"><img src="https://upload.wikimedia.org/wikipedia/commons/9/95/Vue.js_Logo_2.svg" width="20" height="20">VueJs</a></li>
<li><a href="https://www.sqlite.org/"><img src="https://www.vectorlogo.zone/logos/sqlite/sqlite-icon.svg" height="20", width="20">SQLite</a></li>
</ul>
## Tools used
<ul>
<li><a href="https://code.visualstudio.com/"><img src="https://upload.wikimedia.org/wikipedia/commons/9/9a/Visual_Studio_Code_1.35_icon.svg" width="20" height="20"> Visual Studio Code</a></li>
<li><a href="https://www.jetbrains.com/webstorm/"><img src="https://upload.wikimedia.org/wikipedia/commons/c/c0/WebStorm_Icon.svg" width="20" height="20"> JetBrains WebStorm</a></li>
<li><a href="https://www.jetbrains.com/datagrip/"><img src="https://seeklogo.com/images/D/datagrip-logo-295CA63255-seeklogo.com.png" width="20" height="20"> JetBrains DataGrip</a></li>
<li><a href="https://neovim.io/"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/0/07/Neovim-mark-flat.svg/640px-Neovim-mark-flat.svg.png" width="20" height="20"> Neovim</a></li>
<li><a href="https://code.visualstudio.com/"><img src="https://code.visualstudio.com/assets/images/code-stable.png" width="20" height="20"> Visual Studio Code</a></li>
</ul>
---
### Honorable mentions
<ul>
<li><a href="https://oakserver.github.io/oak/"><img src="https://oakserver.org/oak_logo.svg?__frsh_c=2e345d91800d1e0a52aa35efcaab769fa1768888" width="20" height="20"> Oak</a></li>
</ul>

View File

@@ -55,7 +55,7 @@ type ApiResponse = {
};
// database creation if missing, runs here because this is the main file executed by the API.
await db_utils.ensureDatabaseExists();
db_utils.ensureDatabaseExists();
// +++ ROUTER ------------------------------------------------------- //
// Creates the routes for the API server.

View File

@@ -7,10 +7,18 @@
// +++ IMPORTS ------------------------------------------------------ //
import { DB } from "https://deno.land/x/sqlite@v3.9.1/mod.ts";
import {
dirname,
fromFileUrl,
join,
} from "https://deno.land/std@0.224.0/path/mod.ts";
// +++ VARIABLES ---------------------------------------------------- //
const _dirname: string = dirname(fromFileUrl(import.meta.url));
const dbPath: string = join(_dirname, "../database/esp-projekt.sqlite");
const db = new DB(dbPath);
export function createDatabase(db: DB): void {
export function createDatabase(): void {
db.execute(`
CREATE TABLE IF NOT EXISTS accounts (
user_id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -64,17 +72,12 @@ export function createDatabase(db: DB): void {
chat_name TEXT,
participants TEXT,
created_at TEXT
);
CREATE TABLE IF NOT EXISTS marker (
id INTEGER PRIMARY KEY AUTOINCREMENT
);
)
`);
}
// Sample data generated using AI, does not work yet and will be adjusted
export function insertSampleData(db: DB): void {
export function insertSampleData(): void {
db.query(
`INSERT INTO accounts (user_group, bio, displayname, username, user_email, password, password_salt, firstname, surname, account_created, blocked_users, followers, following, contacts) VALUES
('admin', 'Admin bio', 'Admin User', 'admin', 'admin@example.com', 'pw1', 'salt1', 'Admin', 'User', '2024-01-01', '[]', '[]', '[]', '[]'),

Binary file not shown.

View File

@@ -77,53 +77,48 @@ export function queryDatabase<T>(
// +++ DATABASE INITIALIZATION -------------------------------------- //
export async function ensureDatabaseExists(): Promise<void> {
const dbDir = dirname(dbPath);
let dbInstance: DB | null = null; // Avoids hard to decode errors because it Throws one if it cant continue.
try {
// Check if the database directory exists, create it if not
const dbDir = dirname(dbPath);
try {
await Deno.stat(dbDir);
} catch (error) {
if (error instanceof Deno.errors.NotFound) { // Deno.errors.NotFound is a type of error that is thrown when a file or directory is not found.
// In short, It's a type, and it makes sure that the "error" variable is of type Deno.errors.NotFound.
if (error instanceof Deno.errors.NotFound) {
// Create the database directory
await Deno.mkdir(dbDir, { recursive: true });
console.log(`Created database directory: ${dbDir}`);
} else {
throw error;
}
}
console.log(`Opening database connection: ${dbPath}`);
dbInstance = new DB(dbPath);
// Check if the database file exists
try {
dbInstance.query("SELECT 1 FROM marker LIMIT 1;");
console.log("Database already initialized (marker table found).");
await Deno.stat(dbPath);
console.log("Database file already exists");
} catch (error) {
if (error instanceof Error) {
console.log(
"Marker table not found or query failed. Initializing database tables.",
);
db_create.createDatabase(dbInstance);
db_create.insertSampleData(dbInstance);
console.log("Database initialization complete.");
if (error instanceof Deno.errors.NotFound) {
createDatabaseIfNotExist();
insertSamples();
// Nothing, file will be created below
} else {
throw error;
}
}
} catch (error) {
console.error(
"Error during database existence check or initialization:",
error,
);
} finally {
if (dbInstance) {
dbInstance.close();
console.log("Database connection closed.");
} else {
console.log("Database connection was not opened.");
}
console.error("Error ensuring database exists:", error);
throw error;
}
}
export function createDatabaseIfNotExist(): void {
db_create.createDatabase();
}
export function insertSamples(): void {
db_create.insertSampleData();
}
// +++ ACCOUNT FUNCTIONS -------------------------------------------- //
export const getAllUsersFromDB = () => getAllUsersFromDBInternal(db);
export const getUserByUsername = (username: string) =>

346
deno.lock generated
View File

@@ -23,17 +23,12 @@
"npm:autoprefixer@^10.4.20": "10.4.20_postcss@8.4.47",
"npm:path-to-regexp@6.2.1": "6.2.1",
"npm:postcss@^8.4.47": "8.4.47",
"npm:tailwind-scrollbar-hide@2": "2.0.0_tailwindcss@3.4.14__postcss@8.4.47",
"npm:tailwind-scrollbar@^4.0.1": "4.0.1_tailwindcss@4.0.15",
"npm:tailwindcss@*": "3.4.14_postcss@8.4.47",
"npm:tailwindcss@^3.4.14": "3.4.14_postcss@8.4.47",
"npm:typescript@^5.8.2": "5.8.2",
"npm:url@~0.11.4": "0.11.4",
"npm:vite-plugin-checker@~0.9.1": "0.9.1_vite@5.4.10_@types+node@22.5.4",
"npm:vite@*": "5.4.10",
"npm:vite@^5.4.10": "5.4.10",
"npm:vue-router@4": "4.4.5_vue@3.5.12",
"npm:vue-router@^4.5.0": "4.5.0_vue@3.5.12_typescript@5.8.2",
"npm:vue@*": "3.5.12",
"npm:vue@^3.5.12": "3.5.12"
},
@@ -84,14 +79,6 @@
"@alloc/quick-lru@5.2.0": {
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="
},
"@babel/code-frame@7.26.2": {
"integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
"dependencies": [
"@babel/helper-validator-identifier",
"js-tokens",
"picocolors"
]
},
"@babel/helper-string-parser@7.25.9": {
"integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA=="
},
@@ -114,7 +101,7 @@
"@deno/vite-plugin@1.0.0_vite@5.4.10": {
"integrity": "sha512-Q9UeWqs3s7B5lqzu1Z5QrzYAzqTj3+F9YW17tWobGRbT2G40ihwis6zK/+QgMgcG4fm3IqdIfXmpQYhkZpdMfw==",
"dependencies": [
"vite@5.4.10"
"vite"
]
},
"@esbuild/aix-ppc64@0.21.5": {
@@ -304,14 +291,11 @@
"undici-types"
]
},
"@types/prismjs@1.26.5": {
"integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ=="
},
"@vitejs/plugin-vue@5.1.4_vite@5.4.10_vue@3.5.12": {
"integrity": "sha512-N2XSI2n3sQqp5w7Y/AN/L2XDjBIRGqXko+eDp42sydYSBeJuSm5a1sLf8zakmo8u7tA8NmBgoDLA1HeOESjp9A==",
"dependencies": [
"vite@5.4.10",
"vue@3.5.12"
"vite",
"vue"
]
},
"@vue/compiler-core@3.5.12": {
@@ -382,15 +366,7 @@
"dependencies": [
"@vue/compiler-ssr",
"@vue/shared",
"vue@3.5.12"
]
},
"@vue/server-renderer@3.5.12_vue@3.5.12_vue@3.5.12__typescript@5.8.2": {
"integrity": "sha512-I3QoeDDeEPZm8yR28JtY+rk880Oqmj43hreIBVTicisFTx/Dl7JpG72g/X7YF8hnQD3IFhkky5i2bPonwrTVPg==",
"dependencies": [
"@vue/compiler-ssr",
"@vue/shared",
"vue@3.5.12_typescript@5.8.2"
"vue"
]
},
"@vue/shared@3.5.12": {
@@ -418,7 +394,7 @@
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dependencies": [
"normalize-path",
"picomatch@2.3.1"
"picomatch"
]
},
"arg@5.0.2": {
@@ -489,18 +465,9 @@
"is-binary-path",
"is-glob",
"normalize-path",
"readdirp@3.6.0"
"readdirp"
]
},
"chokidar@4.0.3": {
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"dependencies": [
"readdirp@4.1.1"
]
},
"clsx@2.1.1": {
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="
},
"color-convert@2.0.1": {
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dependencies": [
@@ -516,7 +483,7 @@
"cross-spawn@7.0.3": {
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"dependencies": [
"path-key@3.1.1",
"path-key",
"shebang-command",
"which"
]
@@ -615,12 +582,6 @@
"reusify"
]
},
"fdir@6.4.3_picomatch@4.0.2": {
"integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==",
"dependencies": [
"picomatch@4.0.2"
]
},
"fill-range@7.1.1": {
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": [
@@ -740,9 +701,6 @@
"jiti@1.21.6": {
"integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w=="
},
"js-tokens@4.0.0": {
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"lilconfig@2.1.0": {
"integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ=="
},
@@ -768,7 +726,7 @@
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dependencies": [
"braces",
"picomatch@2.3.1"
"picomatch"
]
},
"minimatch@9.0.5": {
@@ -800,13 +758,6 @@
"normalize-range@0.1.2": {
"integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA=="
},
"npm-run-path@6.0.0": {
"integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
"dependencies": [
"path-key@4.0.0",
"unicorn-magic"
]
},
"object-assign@4.1.1": {
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
},
@@ -822,9 +773,6 @@
"path-key@3.1.1": {
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
},
"path-key@4.0.0": {
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="
},
"path-parse@1.0.7": {
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
@@ -844,9 +792,6 @@
"picomatch@2.3.1": {
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
},
"picomatch@4.0.2": {
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="
},
"pify@2.3.0": {
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="
},
@@ -902,14 +847,6 @@
"source-map-js"
]
},
"prism-react-renderer@2.4.1_react@19.0.0": {
"integrity": "sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==",
"dependencies": [
"@types/prismjs",
"clsx",
"react"
]
},
"punycode@1.4.1": {
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="
},
@@ -922,9 +859,6 @@
"queue-microtask@1.2.3": {
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
},
"react@19.0.0": {
"integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ=="
},
"read-cache@1.0.0": {
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
"dependencies": [
@@ -934,12 +868,9 @@
"readdirp@3.6.0": {
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dependencies": [
"picomatch@2.3.1"
"picomatch"
]
},
"readdirp@4.1.1": {
"integrity": "sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw=="
},
"resolve@1.22.8": {
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
"dependencies": [
@@ -1060,25 +991,12 @@
"supports-preserve-symlinks-flag@1.0.0": {
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
},
"tailwind-scrollbar-hide@2.0.0_tailwindcss@3.4.14__postcss@8.4.47": {
"integrity": "sha512-lqiIutHliEiODwBRHy4G2+Tcayo2U7+3+4frBmoMETD72qtah+XhOk5XcPzC1nJvXhXUdfl2ajlMhUc2qC6CIg==",
"dependencies": [
"tailwindcss@3.4.14_postcss@8.4.47"
]
},
"tailwind-scrollbar@4.0.1_tailwindcss@4.0.15": {
"integrity": "sha512-j2ZfUI7p8xmSQdlqaCxEb4Mha8ErvWjDVyu2Ke4IstWprQ/6TmIz1GSLE62vsTlXwnMLYhuvbFbIFzaJGOGtMg==",
"dependencies": [
"prism-react-renderer",
"tailwindcss@4.0.15"
]
},
"tailwindcss@3.4.14_postcss@8.4.47": {
"integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==",
"dependencies": [
"@alloc/quick-lru",
"arg",
"chokidar@3.6.0",
"chokidar",
"didyoumean",
"dlv",
"fast-glob",
@@ -1100,9 +1018,6 @@
"sucrase"
]
},
"tailwindcss@4.0.15": {
"integrity": "sha512-6ZMg+hHdMJpjpeCCFasX7K+U615U9D+7k5/cDK/iRwl6GptF24+I/AbKgOnXhVKePzrEyIXutLv36n4cRsq3Sg=="
},
"thenify-all@1.6.0": {
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
"dependencies": [
@@ -1115,16 +1030,6 @@
"any-promise"
]
},
"tiny-invariant@1.3.3": {
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="
},
"tinyglobby@0.2.12_picomatch@4.0.2": {
"integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==",
"dependencies": [
"fdir",
"picomatch@4.0.2"
]
},
"to-regex-range@5.0.1": {
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dependencies": [
@@ -1134,15 +1039,9 @@
"ts-interface-checker@0.1.13": {
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
},
"typescript@5.8.2": {
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="
},
"undici-types@6.19.8": {
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
},
"unicorn-magic@0.3.0": {
"integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="
},
"update-browserslist-db@1.1.1_browserslist@4.24.2": {
"integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==",
"dependencies": [
@@ -1161,21 +1060,6 @@
"util-deprecate@1.0.2": {
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"vite-plugin-checker@0.9.1_vite@5.4.10_@types+node@22.5.4": {
"integrity": "sha512-neH3CSNWdkZ+zi+WPt/0y5+IO2I0UAI0NX6MaXqU/KxN1Lz6np/7IooRB6VVAMBa4nigqm1GRF6qNa4+EL5jDQ==",
"dependencies": [
"@babel/code-frame",
"chokidar@4.0.3",
"npm-run-path",
"picocolors",
"picomatch@4.0.2",
"strip-ansi@7.1.0",
"tiny-invariant",
"tinyglobby",
"vite@5.4.10_@types+node@22.5.4",
"vscode-uri"
]
},
"vite@5.4.10": {
"integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==",
"dependencies": [
@@ -1185,31 +1069,11 @@
"rollup"
]
},
"vite@5.4.10_@types+node@22.5.4": {
"integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==",
"dependencies": [
"@types/node",
"esbuild",
"fsevents",
"postcss",
"rollup"
]
},
"vscode-uri@3.1.0": {
"integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="
},
"vue-router@4.4.5_vue@3.5.12": {
"integrity": "sha512-4fKZygS8cH1yCyuabAXGUAsyi1b2/o/OKgu/RUb+znIYOxPRxdkytJEx+0wGcpBE1pX6vUgh5jwWOKRGvuA/7Q==",
"dependencies": [
"@vue/devtools-api",
"vue@3.5.12"
]
},
"vue-router@4.5.0_vue@3.5.12_typescript@5.8.2": {
"integrity": "sha512-HDuk+PuH5monfNuY+ct49mNmkCRK4xJAV9Ts4z9UFc4rzdDnxQLyCMGGc8pKhZhHTVzfanpNwB/lwqevcBwI4w==",
"dependencies": [
"@vue/devtools-api",
"vue@3.5.12_typescript@5.8.2"
"vue"
]
},
"vue@3.5.12": {
@@ -1218,21 +1082,10 @@
"@vue/compiler-dom",
"@vue/compiler-sfc",
"@vue/runtime-dom",
"@vue/server-renderer@3.5.12_vue@3.5.12",
"@vue/server-renderer",
"@vue/shared"
]
},
"vue@3.5.12_typescript@5.8.2": {
"integrity": "sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==",
"dependencies": [
"@vue/compiler-dom",
"@vue/compiler-sfc",
"@vue/runtime-dom",
"@vue/server-renderer@3.5.12_vue@3.5.12_vue@3.5.12__typescript@5.8.2",
"@vue/shared",
"typescript"
]
},
"which@2.0.2": {
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dependencies": [
@@ -1260,15 +1113,101 @@
}
},
"redirects": {
"https://deno.land/std/assert/mod.ts": "https://deno.land/std@0.224.0/assert/mod.ts",
"https://deno.land/std/path/mod.ts": "https://deno.land/std@0.224.0/path/mod.ts",
"https://deno.land/std/testing/asserts.ts": "https://deno.land/std@0.224.0/testing/asserts.ts",
"https://deno.land/x/cors/mod.ts": "https://deno.land/x/cors@v1.2.2/mod.ts",
"https://deno.land/x/oak/mod.ts": "https://deno.land/x/oak@v17.1.2/mod.ts",
"https://deno.land/x/sqlite/mod.ts": "https://deno.land/x/sqlite@v3.9.1/mod.ts"
"https://deno.land/x/sqlite/mod.ts": "https://deno.land/x/sqlite@v3.9.1/mod.ts",
"https://deno.land/x/superoak/mod.ts": "https://deno.land/x/superoak@4.8.1/mod.ts"
},
"remote": {
"https://deno.land/std@0.115.0/_wasm_crypto/crypto.js": "1c565287b35f6eb1aa58499d0f4fbac99a9c30eb9a735c512d193a6493499e84",
"https://deno.land/std@0.115.0/_wasm_crypto/crypto.wasm.js": "e93d38b215c05c552669e9565654599b13e7898ebd3f10ac91e39413efda4b84",
"https://deno.land/std@0.115.0/_wasm_crypto/mod.ts": "9afe300945fe7e5bcec231b52b0016d8442d026b823f619bb5939b2cf66ff21b",
"https://deno.land/std@0.115.0/crypto/mod.ts": "8e1ec0ff94a4f08e3c4f72de5b88781566481602614e62291aa7ae7444ba11f0",
"https://deno.land/std@0.115.0/encoding/base64.ts": "0b58bd6477214838bf711eef43eac21e47ba9e5c81b2ce185fe25d9ecab3ebb3",
"https://deno.land/std@0.115.1/async/deadline.ts": "1d6ac7aeaee22f75eb86e4e105d6161118aad7b41ae2dd14f4cfd3bf97472b93",
"https://deno.land/std@0.115.1/async/debounce.ts": "b2f693e4baa16b62793fd618de6c003b63228db50ecfe3bd51fc5f6dc0bc264b",
"https://deno.land/std@0.115.1/async/deferred.ts": "ab60d46ba561abb3b13c0c8085d05797a384b9f182935f051dc67136817acdee",
"https://deno.land/std@0.115.1/async/delay.ts": "f2d8ccaa8ebc26594bd8b0989edfd8a96257a714c1dee2fb54d986e5bdd840ac",
"https://deno.land/std@0.115.1/async/mod.ts": "78425176fabea7bd1046ce3819fd69ce40da85c83e0f174d17e8e224a91f7d10",
"https://deno.land/std@0.115.1/async/mux_async_iterator.ts": "62abff3af9ff619e8f2adc96fc70d4ca020fa48a50c23c13f12d02ed2b760dbe",
"https://deno.land/std@0.115.1/async/pool.ts": "353ce4f91865da203a097aa6f33de8966340c91b6f4a055611c8c5d534afd12f",
"https://deno.land/std@0.115.1/async/tee.ts": "3e9f2ef6b36e55188de16a667c702ace4ad0cf84e3720379160e062bf27348ad",
"https://deno.land/std@0.115.1/fmt/colors.ts": "8368ddf2d48dfe413ffd04cdbb7ae6a1009cf0dccc9c7ff1d76259d9c61a0621",
"https://deno.land/std@0.115.1/http/http_status.ts": "2ff185827bff21c7be2807fcb09a6a2166464ba57fcd94afe805abab8e09070a",
"https://deno.land/std@0.115.1/http/server.ts": "46f616eac1ca0ea7b9fce97102d185a3d97ae7d7d3bbd635b74cefe05ed1cb37",
"https://deno.land/std@0.115.1/testing/_diff.ts": "e6a10d2aca8d6c27a9c5b8a2dbbf64353874730af539707b5b39d4128140642d",
"https://deno.land/std@0.115.1/testing/asserts.ts": "a1fef0239a2c343b0baa49c77dcdd7412613c46f3aba2887c331a2d7ed1f645e",
"https://deno.land/std@0.213.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975",
"https://deno.land/std@0.213.0/assert/_diff.ts": "dcc63d94ca289aec80644030cf88ccbf7acaa6fbd7b0f22add93616b36593840",
"https://deno.land/std@0.213.0/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4",
"https://deno.land/std@0.213.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5",
"https://deno.land/std@0.213.0/assert/assert_almost_equals.ts": "8b96b7385cc117668b0720115eb6ee73d04c9bcb2f5d2344d674918c9113688f",
"https://deno.land/std@0.213.0/assert/assert_array_includes.ts": "1688d76317fd45b7e93ef9e2765f112fdf2b7c9821016cdfb380b9445374aed1",
"https://deno.land/std@0.213.0/assert/assert_equals.ts": "4497c56fe7d2993b0d447926702802fc0becb44e319079e8eca39b482ee01b4e",
"https://deno.land/std@0.213.0/assert/assert_exists.ts": "24a7bf965e634f909242cd09fbaf38bde6b791128ece08e33ab08586a7cc55c9",
"https://deno.land/std@0.213.0/assert/assert_false.ts": "6f382568e5128c0f855e5f7dbda8624c1ed9af4fcc33ef4a9afeeedcdce99769",
"https://deno.land/std@0.213.0/assert/assert_greater.ts": "4945cf5729f1a38874d7e589e0fe5cc5cd5abe5573ca2ddca9d3791aa891856c",
"https://deno.land/std@0.213.0/assert/assert_greater_or_equal.ts": "573ed8823283b8d94b7443eb69a849a3c369a8eb9666b2d1db50c33763a5d219",
"https://deno.land/std@0.213.0/assert/assert_instance_of.ts": "72dc1faff1e248692d873c89382fa1579dd7b53b56d52f37f9874a75b11ba444",
"https://deno.land/std@0.213.0/assert/assert_is_error.ts": "6596f2b5ba89ba2fe9b074f75e9318cda97a2381e59d476812e30077fbdb6ed2",
"https://deno.land/std@0.213.0/assert/assert_less.ts": "2b4b3fe7910f65f7be52212f19c3977ecb8ba5b2d6d0a296c83cde42920bb005",
"https://deno.land/std@0.213.0/assert/assert_less_or_equal.ts": "b93d212fe669fbde959e35b3437ac9a4468f2e6b77377e7b6ea2cfdd825d38a0",
"https://deno.land/std@0.213.0/assert/assert_match.ts": "ec2d9680ed3e7b9746ec57ec923a17eef6d476202f339ad91d22277d7f1d16e1",
"https://deno.land/std@0.213.0/assert/assert_not_equals.ts": "f3edda73043bc2c9fae6cbfaa957d5c69bbe76f5291a5b0466ed132c8789df4c",
"https://deno.land/std@0.213.0/assert/assert_not_instance_of.ts": "8f720d92d83775c40b2542a8d76c60c2d4aeddaf8713c8d11df8984af2604931",
"https://deno.land/std@0.213.0/assert/assert_not_match.ts": "b4b7c77f146963e2b673c1ce4846473703409eb93f5ab0eb60f6e6f8aeffe39f",
"https://deno.land/std@0.213.0/assert/assert_not_strict_equals.ts": "da0b8ab60a45d5a9371088378e5313f624799470c3b54c76e8b8abeec40a77be",
"https://deno.land/std@0.213.0/assert/assert_object_match.ts": "e85e5eef62a56ce364c3afdd27978ccab979288a3e772e6855c270a7b118fa49",
"https://deno.land/std@0.213.0/assert/assert_rejects.ts": "e9e0c8d9c3e164c7ac962c37b3be50577c5a2010db107ed272c4c1afb1269f54",
"https://deno.land/std@0.213.0/assert/assert_strict_equals.ts": "0425a98f70badccb151644c902384c12771a93e65f8ff610244b8147b03a2366",
"https://deno.land/std@0.213.0/assert/assert_string_includes.ts": "dfb072a890167146f8e5bdd6fde887ce4657098e9f71f12716ef37f35fb6f4a7",
"https://deno.land/std@0.213.0/assert/assert_throws.ts": "edddd86b39606c342164b49ad88dd39a26e72a26655e07545d172f164b617fa7",
"https://deno.land/std@0.213.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8",
"https://deno.land/std@0.213.0/assert/equal.ts": "fae5e8a52a11d3ac694bbe1a53e13a7969e3f60791262312e91a3e741ae519e2",
"https://deno.land/std@0.213.0/assert/fail.ts": "f310e51992bac8e54f5fd8e44d098638434b2edb802383690e0d7a9be1979f1c",
"https://deno.land/std@0.213.0/assert/mod.ts": "325df8c0683ad83a873b9691aa66b812d6275fc9fec0b2d180ac68a2c5efed3b",
"https://deno.land/std@0.213.0/assert/unimplemented.ts": "47ca67d1c6dc53abd0bd729b71a31e0825fc452dbcd4fde4ca06789d5644e7fd",
"https://deno.land/std@0.213.0/assert/unreachable.ts": "38cfecb95d8b06906022d2f9474794fca4161a994f83354fd079cac9032b5145",
"https://deno.land/std@0.213.0/async/delay.ts": "8e1d18fe8b28ff95885e2bc54eccec1713f57f756053576d8228e6ca110793ad",
"https://deno.land/std@0.213.0/fmt/colors.ts": "aeaee795471b56fc62a3cb2e174ed33e91551b535f44677f6320336aabb54fbb",
"https://deno.land/std@0.213.0/http/server.ts": "6dce295abc169d0956ae00432441331b3425afad4d79e8b3475739be2f04d614",
"https://deno.land/std@0.213.0/http/status.ts": "ed61b4882af2514a81aefd3245e8df4c47b9a8e54929a903577643d2d1ebf514",
"https://deno.land/std@0.224.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975",
"https://deno.land/std@0.224.0/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834",
"https://deno.land/std@0.224.0/assert/assert_almost_equals.ts": "9e416114322012c9a21fa68e187637ce2d7df25bcbdbfd957cd639e65d3cf293",
"https://deno.land/std@0.224.0/assert/assert_array_includes.ts": "14c5094471bc8e4a7895fc6aa5a184300d8a1879606574cb1cd715ef36a4a3c7",
"https://deno.land/std@0.224.0/assert/assert_equals.ts": "3bbca947d85b9d374a108687b1a8ba3785a7850436b5a8930d81f34a32cb8c74",
"https://deno.land/std@0.224.0/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd",
"https://deno.land/std@0.224.0/assert/assert_false.ts": "3e9be8e33275db00d952e9acb0cd29481a44fa0a4af6d37239ff58d79e8edeff",
"https://deno.land/std@0.224.0/assert/assert_greater.ts": "5e57b201fd51b64ced36c828e3dfd773412c1a6120c1a5a99066c9b261974e46",
"https://deno.land/std@0.224.0/assert/assert_greater_or_equal.ts": "9870030f997a08361b6f63400273c2fb1856f5db86c0c3852aab2a002e425c5b",
"https://deno.land/std@0.224.0/assert/assert_instance_of.ts": "e22343c1fdcacfaea8f37784ad782683ec1cf599ae9b1b618954e9c22f376f2c",
"https://deno.land/std@0.224.0/assert/assert_is_error.ts": "f856b3bc978a7aa6a601f3fec6603491ab6255118afa6baa84b04426dd3cc491",
"https://deno.land/std@0.224.0/assert/assert_less.ts": "60b61e13a1982865a72726a5fa86c24fad7eb27c3c08b13883fb68882b307f68",
"https://deno.land/std@0.224.0/assert/assert_less_or_equal.ts": "d2c84e17faba4afe085e6c9123a63395accf4f9e00150db899c46e67420e0ec3",
"https://deno.land/std@0.224.0/assert/assert_match.ts": "ace1710dd3b2811c391946954234b5da910c5665aed817943d086d4d4871a8b7",
"https://deno.land/std@0.224.0/assert/assert_not_equals.ts": "78d45dd46133d76ce624b2c6c09392f6110f0df9b73f911d20208a68dee2ef29",
"https://deno.land/std@0.224.0/assert/assert_not_instance_of.ts": "3434a669b4d20cdcc5359779301a0588f941ffdc2ad68803c31eabdb4890cf7a",
"https://deno.land/std@0.224.0/assert/assert_not_match.ts": "df30417240aa2d35b1ea44df7e541991348a063d9ee823430e0b58079a72242a",
"https://deno.land/std@0.224.0/assert/assert_not_strict_equals.ts": "37f73880bd672709373d6dc2c5f148691119bed161f3020fff3548a0496f71b8",
"https://deno.land/std@0.224.0/assert/assert_object_match.ts": "411450fd194fdaabc0089ae68f916b545a49d7b7e6d0026e84a54c9e7eed2693",
"https://deno.land/std@0.224.0/assert/assert_rejects.ts": "4bee1d6d565a5b623146a14668da8f9eb1f026a4f338bbf92b37e43e0aa53c31",
"https://deno.land/std@0.224.0/assert/assert_strict_equals.ts": "b4f45f0fd2e54d9029171876bd0b42dd9ed0efd8f853ab92a3f50127acfa54f5",
"https://deno.land/std@0.224.0/assert/assert_string_includes.ts": "496b9ecad84deab72c8718735373feb6cdaa071eb91a98206f6f3cb4285e71b8",
"https://deno.land/std@0.224.0/assert/assert_throws.ts": "c6508b2879d465898dab2798009299867e67c570d7d34c90a2d235e4553906eb",
"https://deno.land/std@0.224.0/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917",
"https://deno.land/std@0.224.0/fs/exists.ts": "3d38cb7dcbca3cf313be343a7b8af18a87bddb4b5ca1bd2314be12d06533b50f",
"https://deno.land/std@0.224.0/assert/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47",
"https://deno.land/std@0.224.0/assert/fail.ts": "0eba674ffb47dff083f02ced76d5130460bff1a9a68c6514ebe0cdea4abadb68",
"https://deno.land/std@0.224.0/assert/mod.ts": "48b8cb8a619ea0b7958ad7ee9376500fe902284bb36f0e32c598c3dc34cbd6f3",
"https://deno.land/std@0.224.0/assert/unimplemented.ts": "8c55a5793e9147b4f1ef68cd66496b7d5ba7a9e7ca30c6da070c1a58da723d73",
"https://deno.land/std@0.224.0/assert/unreachable.ts": "5ae3dbf63ef988615b93eb08d395dda771c96546565f9e521ed86f6510c29e19",
"https://deno.land/std@0.224.0/fmt/colors.ts": "508563c0659dd7198ba4bbf87e97f654af3c34eb56ba790260f252ad8012e1c5",
"https://deno.land/std@0.224.0/internal/diff.ts": "6234a4b493ebe65dc67a18a0eb97ef683626a1166a1906232ce186ae9f65f4e6",
"https://deno.land/std@0.224.0/internal/format.ts": "0a98ee226fd3d43450245b1844b47003419d34d210fa989900861c79820d21c2",
"https://deno.land/std@0.224.0/internal/mod.ts": "534125398c8e7426183e12dc255bb635d94e06d0f93c60a297723abe69d3b22e",
"https://deno.land/std@0.224.0/path/_common/assert_path.ts": "dbdd757a465b690b2cc72fc5fb7698c51507dec6bfafce4ca500c46b76ff7bd8",
"https://deno.land/std@0.224.0/path/_common/basename.ts": "569744855bc8445f3a56087fd2aed56bdad39da971a8d92b138c9913aecc5fa2",
"https://deno.land/std@0.224.0/path/_common/common.ts": "ef73c2860694775fe8ffcbcdd387f9f97c7a656febf0daa8c73b56f4d8a7bd4c",
@@ -1346,6 +1285,7 @@
"https://deno.land/std@0.224.0/path/windows/resolve.ts": "8dae1dadfed9d46ff46cc337c9525c0c7d959fb400a6308f34595c45bdca1972",
"https://deno.land/std@0.224.0/path/windows/to_file_url.ts": "40e560ee4854fe5a3d4d12976cef2f4e8914125c81b11f1108e127934ced502e",
"https://deno.land/std@0.224.0/path/windows/to_namespaced_path.ts": "4ffa4fb6fae321448d5fe810b3ca741d84df4d7897e61ee29be961a6aac89a4c",
"https://deno.land/std@0.224.0/testing/asserts.ts": "d0cdbabadc49cc4247a50732ee0df1403fdcd0f95360294ad448ae8c240f3f5c",
"https://deno.land/x/cors@v1.2.2/abcCors.ts": "cdf83a7eaa69a1bf3ab910d18b9422217902fac47601adcaf0afac5a61845d48",
"https://deno.land/x/cors@v1.2.2/attainCors.ts": "7d6aba0f942495cc31119604e0895c9bb8edd8f8baa7fe78e6c655bd0b4cbf59",
"https://deno.land/x/cors@v1.2.2/cors.ts": "0e2d9167e3685f9bcf48f565e312b6e1883fa458f7337e5ce7bc2e3b29767980",
@@ -1354,6 +1294,7 @@
"https://deno.land/x/cors@v1.2.2/oakCors.ts": "1348dc7673c61b85d2e80559a7b44f8e0246eaa6bcc6ec744fafe5d9b13b5c71",
"https://deno.land/x/cors@v1.2.2/opineCors.ts": "fb5790115c26b7061d84b8d6c17d258a1e241bcab75b0bc3ca1fdb2e57bc5072",
"https://deno.land/x/cors@v1.2.2/types.ts": "97546633ccc7f0df7a29bacba5d91dc6f61decdd1b65258300244dba905d34b8",
"https://deno.land/x/free_port@v1.2.0/mod.ts": "512646732aaea41fbfd1f210f3ae82660f38251777d189d290da331d0235a58e",
"https://deno.land/x/oak@v17.1.2/application.ts": "2bcc73b3f22a193554c9958f7080ea635db25594d25ff7944021fca5bf74adba",
"https://deno.land/x/oak@v17.1.2/body.ts": "0eb7ab9df44d1b79933463d596b5e1a4f0991c94cff591861e58a413bda3f3db",
"https://deno.land/x/oak@v17.1.2/context.ts": "345cfdaa5a2310558ee0863f2fba5f9ba648188412b16ce342c33266c085f5d3",
@@ -1383,6 +1324,10 @@
"https://deno.land/x/oak@v17.1.2/utils/resolve_path.ts": "aa39d54a003b38fee55f340a0cba3f93a7af85b8ddd5fbfb049a98fc0109b36d",
"https://deno.land/x/oak@v17.1.2/utils/streams.ts": "3da73b94681f8d27a82cc67df3f91090ec0bd6c3e9ab957af588d41ab585d923",
"https://deno.land/x/oak@v17.1.2/utils/type_guards.ts": "a8dbb5ab7424f0355b121537d2454f927e0ca9949262fb67ac4fbefbd5880313",
"https://deno.land/x/opine@1.9.1/src/methods.ts": "0481daecc6068d24e9e5391818baddf555ab803d39a465dcd259161f8bd8ee49",
"https://deno.land/x/opine@1.9.1/src/utils/mergeDescriptors.ts": "1fe498d4a1a8dcfd3570f9ca5e0647590d86d029b3c340bfcfdb57002851e41b",
"https://deno.land/x/opine@2.3.4/src/methods.ts": "0481daecc6068d24e9e5391818baddf555ab803d39a465dcd259161f8bd8ee49",
"https://deno.land/x/opine@2.3.4/src/utils/mergeDescriptors.ts": "1fe498d4a1a8dcfd3570f9ca5e0647590d86d029b3c340bfcfdb57002851e41b",
"https://deno.land/x/sqlite@v3.2.0/build/sqlite.js": "16fe819f3b40c0d2e100014ec922b7dcef32bc9a0c799a9ecd4f1ae104217c88",
"https://deno.land/x/sqlite@v3.2.0/build/vfs.js": "baff72655c0916c906327fe6703c6a47daa1346e55c2eaa2629bcd879a673c8d",
"https://deno.land/x/sqlite@v3.2.0/mod.ts": "0b3e066f61a149d5aa99a50e2c41c687eaa0713350d3e9bfbe4025173ec1c9a9",
@@ -1399,7 +1344,77 @@
"https://deno.land/x/sqlite@v3.9.1/src/error.ts": "f7a15cb00d7c3797da1aefee3cf86d23e0ae92e73f0ba3165496c3816ab9503a",
"https://deno.land/x/sqlite@v3.9.1/src/function.ts": "bc778cab7a6d771f690afa27264c524d22fcb96f1bb61959ade7922c15a4ab8d",
"https://deno.land/x/sqlite@v3.9.1/src/query.ts": "d58abda928f6582d77bad685ecf551b1be8a15e8e38403e293ec38522e030cad",
"https://deno.land/x/sqlite@v3.9.1/src/wasm.ts": "e79d0baa6e42423257fb3c7cc98091c54399254867e0f34a09b5bdef37bd9487"
"https://deno.land/x/sqlite@v3.9.1/src/wasm.ts": "e79d0baa6e42423257fb3c7cc98091c54399254867e0f34a09b5bdef37bd9487",
"https://deno.land/x/superdeno@4.7.0/deps.ts": "af7a0bc4c15710e0d7eb3e36b8ebf0f97debe394062ddf952c9f2b8160c6a590",
"https://deno.land/x/superdeno@4.7.0/mod.ts": "fa91c501867a4302a4bc92d63cbf934fe5475ebb7bf58335338e001147263c87",
"https://deno.land/x/superdeno@4.7.0/src/close.ts": "3d8bb8c24ab62cf6ce7aa9bff8ed35c0fcba5c9e4d90d0bf93fe2868a97b25e5",
"https://deno.land/x/superdeno@4.7.0/src/superagent.ts": "8f60187f9278b154ef6bccf09a5ff7d45f81103ad0ce02d45518a6bbe63ce764",
"https://deno.land/x/superdeno@4.7.0/src/superdeno.ts": "e27b490f34e170c5f103503c722293cefc351b1ac767246dfcb95d204e4a6953",
"https://deno.land/x/superdeno@4.7.0/src/test.ts": "d14892194d6911ba40de898884a50831468f47631a09178aef8fb61aa00ec1f6",
"https://deno.land/x/superdeno@4.7.0/src/types.ts": "0fc4a0a1acf4c3acba3e3d956a9e8917ce32cd47dbb8e75ffadec21a43a8e52f",
"https://deno.land/x/superdeno@4.7.0/src/utils.ts": "458c1699f73e348745b9b4d081e005dbc12d050fd2899ebf4f919515823ba1c0",
"https://deno.land/x/superdeno@4.7.0/src/xhrSham.js": "2db048613ca2fa2aa4ca9df2074411f8403ad4d88a8fb1e87313cee40e2c4a0d",
"https://deno.land/x/superdeno@4.7.0/version.ts": "4a24eb54df1fa633019ba3a4cae82032dc13c0e16bd9813a3aad95e1d5ea91e5",
"https://deno.land/x/superdeno@4.9.0/deps.ts": "acb88a5969aae0bcc82e053cb433cd183a10cc656495caa634b6e22a79156c4e",
"https://deno.land/x/superdeno@4.9.0/mod.ts": "fa91c501867a4302a4bc92d63cbf934fe5475ebb7bf58335338e001147263c87",
"https://deno.land/x/superdeno@4.9.0/src/close.ts": "8bd4ab602ebbb048d06697d0c48c30be5f78ab9ad673850965e8014d78cca7a8",
"https://deno.land/x/superdeno@4.9.0/src/superagent.ts": "8f60187f9278b154ef6bccf09a5ff7d45f81103ad0ce02d45518a6bbe63ce764",
"https://deno.land/x/superdeno@4.9.0/src/superdeno.ts": "2e2cd4898961ac7688f0c2a4b210bf560a338f6601bd231d74bf8a0956880311",
"https://deno.land/x/superdeno@4.9.0/src/test.ts": "1ab3c8c98160af8c3b30e097809d5c57bdd38d7b42c703f3f170f8452ad06c0f",
"https://deno.land/x/superdeno@4.9.0/src/types.ts": "9a48cdfafad3cea2212e1be29cdd2055e7d3d467437c9048012797323335abbb",
"https://deno.land/x/superdeno@4.9.0/src/utils.ts": "09a2e65cc5cc2a261b885f0e66ee84e96e978181975a0728636d20e48b67bd89",
"https://deno.land/x/superdeno@4.9.0/src/xhrSham.js": "6a35aed77bbe98324fe3b4d7430463b7cd6d3b43445ffdccd1fc327dc59dd3c6",
"https://deno.land/x/superdeno@4.9.0/version.ts": "4f8ba8f2a6b201e8e96818d3ab5c43aef1db751523c4b79160500664b72f87de",
"https://deno.land/x/superoak@4.5.0/deps.ts": "17bc881921ae2d3829d6e1168f29374de287c4d460d5288e6b5a6134e7508e5b",
"https://deno.land/x/superoak@4.5.0/mod.ts": "6d4ea8a5a48c9007f2e947934889c06259d3ebb5569515bcb0432036a22449cd",
"https://deno.land/x/superoak@4.5.0/src/superoak.ts": "9c08a3211c4d1f7bb89e88fc3f242536fce654c157aa6db52d3c24f033bb3d28",
"https://deno.land/x/superoak@4.5.0/version.ts": "af59786fbab2ab31ea2aa97927e98d8778407938bad4b531805b6166c064e847",
"https://deno.land/x/superoak@4.8.1/deps.ts": "d716c0b36fdac6458f6984ce80f69d0b645c7e0ac8461024a40ead5ed3fcd08d",
"https://deno.land/x/superoak@4.8.1/mod.ts": "6d4ea8a5a48c9007f2e947934889c06259d3ebb5569515bcb0432036a22449cd",
"https://deno.land/x/superoak@4.8.1/src/superoak.ts": "9c08a3211c4d1f7bb89e88fc3f242536fce654c157aa6db52d3c24f033bb3d28",
"https://deno.land/x/superoak@4.8.1/version.ts": "b9b71ac3596ff0a6aaad2bf9df8a54fb2925abd526800879e261de9c693812bc",
"https://jspm.dev/npm:call-bind@1.0.5!cjs": "09f8399c727fc1e9d58fdafc0a729b45bf37b7ee0c11d9d0b39abe37ac42ccf5",
"https://jspm.dev/npm:call-bind@1.0.5/callBound!cjs": "55fa05e2b115eeaef9ff684e3df12de253e6644a40ad09b5722f3a9a8df8f645",
"https://jspm.dev/npm:call-bind@1/callBound!cjs": "9cf2ef160025d392767618c2f0cb72d32cf14caa3fbeb493c6df9bde9d7fca8d",
"https://jspm.dev/npm:component-emitter@1!cjs": "26c2994a5fcac1cd9156b00be96c5e2f006dd76338095a96006ac3a47c6c327d",
"https://jspm.dev/npm:component-emitter@1.3.0!cjs": "757cafefb0bf5639f3f90b2267a7d168e03631e731c2a79fca847b735695e196",
"https://jspm.dev/npm:define-data-property@1!cjs": "37b65cb06c826730306a5f766de69da37b96076c96ea11a47667e9429623f937",
"https://jspm.dev/npm:define-data-property@1.1.1!cjs": "4ac6fa4b9d7ba7ccc83ffa350c58112ee878a450a97375217f66508d5673c822",
"https://jspm.dev/npm:fast-safe-stringify@2!cjs": "d8dd0803af23f037ffb44c13e18333131af27ebe582f55fd498b6e3c8f6d5a9d",
"https://jspm.dev/npm:fast-safe-stringify@2.1.1!cjs": "8a14a2de8a07a719c74aa63ffa5ff635fc55e9ee5d5a79fbc2e087dc4aa1940e",
"https://jspm.dev/npm:function-bind@1!cjs": "73fbc50bf85e8a6ca150609e98c396301c1ae5a1603e50ce8c64e95f646e0ce0",
"https://jspm.dev/npm:function-bind@1.1.2!cjs": "bbb663bc4e50f400a8ca0de9e0bfdaaa7022695f86b2806a48dc1afc5b4195a8",
"https://jspm.dev/npm:function-bind@1.1.2/implementation!cjs": "ebdc0ec85854db19d7e21081b368891394f86e21c6d786273c327762cb46ea6a",
"https://jspm.dev/npm:get-intrinsic@1!cjs": "f6d9266edc586632e8f6d8d6c5ca28fb2c0d5ee9c9d9252df9aafd57eda9fcea",
"https://jspm.dev/npm:get-intrinsic@1.2.2!cjs": "723fcebc493a45d5af8ecb366020a6cc2ce9bd4759bad699c1172015cb193f65",
"https://jspm.dev/npm:gopd@1!cjs": "c220469947b77de2c5e4b115beda16397bf6133c5b873b8e24e85b902ee6dc82",
"https://jspm.dev/npm:gopd@1.0.1!cjs": "b38da4f4b49cfef31e3aa8d62fdd136cf0fe99a5df6c603a426f97248f3cf4ab",
"https://jspm.dev/npm:has-property-descriptors@1!cjs": "b1a828f75a22a5614b136dd3da1be98cc744a2cd6bfed9bd8c338a8d51a570d1",
"https://jspm.dev/npm:has-property-descriptors@1.0.1!cjs": "f8da64823507f597f3cb44a2f3576e350df72e1033ef5e7a5b30d771e81c0819",
"https://jspm.dev/npm:has-proto@1!cjs": "78a2914e5525d531426c5d69fd5aa23671ec359c6c527b9791327f60ad1b6682",
"https://jspm.dev/npm:has-proto@1.0.1!cjs": "0a9d605f1d310f859265780011d6343a7869cadf3a9e02fd6cc949c2924b528c",
"https://jspm.dev/npm:has-symbols@1!cjs": "48faf647d225b64fa235ccc3e5a848e72221b0230935e421066a5de39aa89c3a",
"https://jspm.dev/npm:has-symbols@1.0.3!cjs": "36965f84e4e0ea1abeddb6928d0719a2648e61ceb9825df185b40d05cddb64df",
"https://jspm.dev/npm:has-symbols@1.0.3/shams!cjs": "669673e1dc7691c0b397580760121d57f3a5c5101dd70be2e8dd7d2a044de2e9",
"https://jspm.dev/npm:hasown@2!cjs": "9a39af846b167cae93b7a40f1ba4c97255bb5b07a1481da853a29bb68d24e603",
"https://jspm.dev/npm:hasown@2.0.0!cjs": "f52fd2477e345530f759465a984023f23d8261c4a54970e619daf1da6a2e85f5",
"https://jspm.dev/npm:object-inspect@1!cjs": "dc197b471ed55ecf2eabeb8da9aaee277e97831e65192531432a4ec2346211d9",
"https://jspm.dev/npm:object-inspect@1.13.1!cjs": "cec116e5c2b7d6b75e178d2541d70475d716ad912e3d5599e5c2d97284a9cb3e",
"https://jspm.dev/npm:qs@6!cjs": "210de1e090ac836c2495c19dfea88fc74b49de1b308241f8c9490d27ab6e0195",
"https://jspm.dev/npm:qs@6.11.2!cjs": "5da52fff60f7b1a6b1c73cdea2d9fc5d5588fa6c551b2a0ea2a1ebbb2a5e559f",
"https://jspm.dev/npm:qs@6.11.2/_/e71c21de.js": "cfe49eb949fb7291803f1ed2f4c0a244b8fca3b6936f5082fc97581a0663e427",
"https://jspm.dev/npm:qs@6.11.2/lib/stringify!cjs": "35d39c5871af151efe9ccca8e4ebecbf0282f97287b5fad56ebac369f69c2581",
"https://jspm.dev/npm:set-function-length@1!cjs": "b4c766d874ba261ff0c11aa18a6bf4510ecf8da09a7219da83a62772e0bc1b41",
"https://jspm.dev/npm:set-function-length@1.1.1!cjs": "f52607660d1f50e19e645ab49e6a4adf27fa4ae909867ec9950e993c430e4ca1",
"https://jspm.dev/npm:side-channel@1!cjs": "a07dfe7165af0d7f916d089490c38839397abcd8b218e4566b270858c9a0ea04",
"https://jspm.dev/npm:side-channel@1.0.4!cjs": "db65b31b6f9e67d57f04e26d71eb5b376306f5a89ab46fae1278c3ffefb19663",
"https://jspm.dev/npm:superagent@6.1.0!cjs": "fcf1c0b17cb3ff899b59ae178fc4ab74ad3b592d7fa8b44b16394001758e3176",
"https://jspm.dev/npm:superagent@6.1.0/lib/agent-base!cjs": "cfe465965a55d80114d835143717413945d0bbc46355d0f7f8200a89902ed006",
"https://jspm.dev/npm:superagent@6.1.0/lib/is-object!cjs": "95f67ff49b42fd5e82114b9d54a4b3fe1ac98813aed7ceaf53d314983f59820a",
"https://jspm.dev/npm:superagent@6.1.0/lib/request-base!cjs": "e361c341aa75d7417c918bc8fb697d0ccf96101e039dd2f00e5e45c01c534caa",
"https://jspm.dev/npm:superagent@6.1.0/lib/response-base!cjs": "00ac549f34d73c2753caa798aa7eb781051179013e3418ff0868a1e1904a8913",
"https://jspm.dev/npm:superagent@6.1.0/lib/utils!cjs": "ea706523553983c96ef4ab2f191c61c53fb8b78ad8ff2472b48f1385e896c030",
"https://jspm.dev/superagent@6.1.0": "4b3082d71252c42abd3930d85d1f3c4b2e937e0fab2b5f1c9d19eac20dea89a9"
},
"workspace": {
"dependencies": [
@@ -1415,12 +1430,7 @@
"packageJson": {
"dependencies": [
"npm:@deno/vite-plugin@1",
"npm:@vitejs/plugin-vue@^5.1.4",
"npm:tailwind-scrollbar-hide@2",
"npm:tailwind-scrollbar@^4.0.1",
"npm:typescript@^5.8.2",
"npm:vite-plugin-checker@~0.9.1",
"npm:vue-router@^4.5.0"
"npm:@vitejs/plugin-vue@^5.1.4"
]
}
}

View File

@@ -1,13 +1,13 @@
<!Doctype html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="src/assets/esp-logo_no_text.png" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ESP - Express, Share, Post</title>
<title>Vite + Vue + TS</title>
<link rel="stylesheet" href="/src/assets/main.css" />
</head>
<body class="bg-hintergrund-farbe sm:overflow-hidden">
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>

991
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,6 @@
{
"dependencies": {
"@deno/vite-plugin": "^1.0.0",
"@vitejs/plugin-vue": "^5.1.4",
"tailwind-scrollbar": "^4.0.1",
"tailwind-scrollbar-hide": "^2.0.0",
"vue-router": "^4.5.0"
},
"devDependencies": {
"typescript": "^5.8.2",
"vite-plugin-checker": "^0.9.1"
"@vitejs/plugin-vue": "^5.1.4"
}
}

View File

@@ -1,6 +0,0 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@@ -1,3 +1,3 @@
<template >
<template>
<router-view />
</template>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 501 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 538 B

View File

@@ -1,5 +1,3 @@
@plugin 'tailwind-scrollbar';
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -4,18 +4,21 @@ import Contacts from "./home_components/contacts.vue";
import Legal from "./home_components/legal.vue";
import Navigationbar from "./home_components/navigationbar.vue";
import Trending from "./home_components/trending.vue";
import QuickSearch from "./home_components/quick_search.vue";
</script>
<template>
<div id="main" class="sm:flex overflow-y-auto sm:h-full sm:scrollbar">
<div id="left" class="sm:w-72 min-w-72">
<div id="main" class="bg-hintergrund-farbe flex">
<div id="left" class="border border-b-grau w-72">
<navigationbar></navigationbar>
<trending></trending>
</div>
<div class="sm:w-100p w-screen">
<div class="w-100p">
<feed></feed>
</div>
<div class="sm:w-1/4 w-screen">
<div class="w-1/4">
<quick-search></quick-search>
<contacts></contacts>
<legal></legal>
</div>

View File

@@ -2,21 +2,15 @@
import Legal from "./home_components/legal.vue";
import Login_comp from "./login_components/login_comp.vue";
import router from "../router";
function route_home() {
router.push("/");
}
</script>
<template>
<div id="main" class="bg-hintergrund-farbe sm:flex sm:p-2 sm:justify-between ">
<div class="pt-5 pl-2">
<img src="../assets/esp-logo_no_text.png" alt="" class=" rounded-lg h-12 w-24 hover:shadow-2xl hover:shadow-grau-dunkel" @click="route_home">
<div id="main" class="bg-hintergrund-farbe flex p-2 ">
<div class="items-center pr-96 pl-2 pt-5">
<img src="../assets/esp-logo_no_text.png" alt="" class="rounded-lg h-12 w-24 mx-auto">
</div>
<login_comp class="inset-0"></login_comp>
<div class="md:inset-y-0 sm:right-0 sm:max-w-36 text-center">
<login_comp></login_comp>
<div class="p-5 ">
<legal></legal>
</div>
</div>

View File

@@ -0,0 +1,38 @@
<script setup lang="ts">
import { ref } from 'vue'
defineProps<{ msg: string }>()
const count = ref(0)
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p>
Install
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
in your IDE for a better DX
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>

View File

@@ -1,21 +1,9 @@
<script setup lang="ts">
import { ref } from 'vue';
import Popup_chat from "./popup_chat.vue";
const contacts = [
{ display_name: "Linux Enjoyer", username: "lunix" },
{ display_name: "XBOX", username: "xbox" },
{ display_name: "JETBrains", username: "jetbrains" },
{ display_name: "klopupser13", username: "theopampa",}
];
const selectedContact = ref(null);
const showChatPopup = ref(false);
function openChat(contact) {
selectedContact.value = contact;
showChatPopup.value = true;
}
const contacts =[
{display_name: "Linux Enjoyer", username: "lunix"},
{display_name: "XBOX", username: "Xbox"},
{display_name: "JETBrains", username: "Jetbrains"},
]
</script>
<template>
@@ -25,19 +13,19 @@ function openChat(contact) {
</div>
<div> <!--CONTENT-->
<ul class="space-y-1">
<li v-for="(contact) in contacts" :key="contact.username" @click="openChat(contact)" class="flex rounded-lg p-2 cursor-pointer">
<li v-for="(contact) in contacts" :key="contact" class="flex rounded-lg">
<!--CONTACT-->
<img src="../../assets/default_pp.png" alt="" class="w-12 h-12 mr-2"> <!--PROFILBILD-->
<img src="../../assets/default_pp.png" alt="" class="w-12 h-12 mr-2">
<div class="">
<label class="font-bold m-1 text-weiss">{{ contact.display_name }}</label><br> <!-- display name-->
<p class="text-base m-1 text-grau2 underline-offset-3">@{{ contact.username }}</p> <!-- username-->
<label class=" font-bold m-1 text-weiss">{{ contact.display_name }}</label><br>
<p class="text-base m-1 text-grau2 underline-offset-3">@{{ contact.username }}</p>
</div>
</li>
</ul>
</div>
<popup_chat v-if="showChatPopup" :contact="selectedContact" @close="showChatPopup = false" />
</div>
</template>
<style scoped>
</style>

View File

@@ -1,176 +1,105 @@
<script setup lang="ts">
import {onMounted, ref} from "vue";
import router from "../../router";
// PLACEHOLDER
const upc = ref([]); // user post computed
let post_create_text = "";
let self_id ;
import { ref } from "vue";
// import {valueOf} from "tailwindcss";
const post = ref([
{id: 1,
profile_picture: "../../assets/default_pp.png",
author_display_name: "Linux Enjoyer",author_username: "lunix",
content:"I love Linux. My Favorite Linux Distro is ARCH LINUX.",
comments_count: 1, likes: 5},
{id: 2,
profile_picture: "../../assets/default_pp.png",
author_display_name: "XBOX",author_username: "Xbox",
content: "Call of Duty: Black Ops 6 is OUT NOW.",
comments_count: 500000, likes: 100000},
{id: 3,
profile_picture: "../../assets/default_pp.png",
author_display_name: "JETBrains",author_username: "Jetbrains",
content: "BLI BLA BLUB. Jetbrains is the best IDE." ,
comments_count: 5000, likes: 1000},
{id: 4,
profile_picture: "../../assets/default_pp.png",
author_display_name: "GITHUB", author_username: "GitHub",
content: "GitHub Copilot got an massive update. Check out the new features.",
comments_count: 1500000, likes: 500000},
{id: 5,
profile_picture: "../../assets/danielvici_pp.png",
author_display_name: "danielvici123", author_username: "danielvici",
content: "I created this WebApp with VUE3 and TailwindCSS. It was a lot of fun.",
comments_count: undefined, likes: 532844},
{id: 6,
profile_picture: "../../assets/default_pp.png",
author_display_name: "Microsoft", author_username: "Microsoft",
content: "Windows 11 24H2 is out now. Learn more here: https://www.microsoft.com",
comments_count: 500000, likes: 100000},
{id: 7,
profile_picture: "../../assets/default_pp.png",
author_display_name: "Apple", author_username: "Apple",
content: "The new iPhone 16 is out now. Everything you need to know: https://www.apple.com",
comments_count: 500000, likes: 100000},
])
onMounted(async () => {
self_id = localStorage.getItem("self_id");
await createFeed();
});
const addLike = (index: number) => {
post.value[index].likes += 1;
console.log("New Like Amount: ", post.value[index].likes);
async function createFeed() {
try {
// posts und user holen und schauen ob sie richtig sidn
const post_response = await fetch('http://localhost:8000/api/posts', { method: 'GET' });
const postsDATA = await post_response.json();
const user_response = await fetch('http://localhost:8000/api/users', { method: 'GET' });
const usersDATA = await user_response.json();
if(post_response.status === 404 || user_response.status === 404) {
console.error("ERRROR");
await router.push('/');
}
function post_publish_func(text:string) {
console.log("Post: ", text);
if (text === undefined || text === "") {
console.log("Post is empty");
alert("Post is empty");
return;
} else {
console.log("Post is not empty");
post.value.push({id: post.value.length + 1, profile_picture: "../../assets/danielvici_pp.png", author_display_name: "ADMIN", author_username: "esp_admin", content: text, comments_count: undefined, likes: 0});
}
// posts und user kombinieren
const combinedPosts = postsDATA.map(post => {
const user = usersDATA.find(user => user.user_id === post.user_id);
return {
post_id: post.posts_uuid,
post_text: post.post_text,
likes: post.likes,
comments: post.comments,
displayname: user ? user.displayname : 'Unknown',
username: user ? user.username : 'unknown_user',
user_id: post.user_id,
};
});
//upc.value = combinedPosts;
upc.value = combinedPosts.sort((a, b) => b.post_id - a.post_id);;
} catch (e) {
console.error("An error has occurred. Please try again later.");
console.error(e);
}
console.log(upc.value);
}
async function addLike(post_id: string | number, user_id: number, index: number) {
try {
console.log("UPC: ", upc.value);
console.log("post_id: ", post_id);
upc.value[index].likes++;
const response = await fetch(`http://localhost:8000/api/post/${post_id}/like`, {
method: 'POST',
headers: {'content-type': 'application/json'},
body: `{"userId":${user_id}}`,
});
console.log('Antwort-Status:', response.status);
if (!response.ok) {
const errorText = await response.text();
console.error('Server-Fehlertext:', errorText);
//upc.value[index].likes--;
throw new Error(`HTTP error! status: ${response.status}, text: ${errorText}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Fehler beim Liken des Posts:', error);
throw error;
}
}
async function post_create(post_text: string) {
if (post_text === "") {
alert("Please write something before posting.");
return;
}
console.log(self_id);
console.log(post_text);
const response = await fetch(`http://localhost:8000/api/post/create`, {
method: 'POST',
headers: {'content-type': 'application/json'},
body: `{"userId":${self_id},"postText":"${post_create_text}","postType":"text"}`});
const data = await response.json();
if (response.ok) {
console.log(response.text);
await createFeed();
}
console.log(data);
console.log(post_text);
}
function gotoPost(post_id: string | number) {
localStorage.setItem("viewedpost", post_id.toString());
router.push(`/post/${post_id}`);
}
function copyLink(post_id: string | number) {
const tocopy = `http://localhost:5173/post/${post_id}`;
navigator.clipboard.writeText(tocopy);
alert("Copied to clipboard");
}
function gotoProfile(user_id: string | number) {
router.push(`/profile/${user_id}`);
}
</script>
<template>
<div class="sm:border-x sm:border-x-grau2"> <!-- MAIN -->
<div class="border-x-2 border-x-grau2"> <!-- MAIN -->
<div> <!-- FEED HEADER -->
<h2 class="align-middle p-6 text-3xl text-weiss border-b-grau2 border-b-2 ">Feed</h2>
<h2 class="align-middle p-6 text-xl font-bold text-grau2 border-b-grau2 border-b ">Feed</h2>
<!-- POSTING-->
<div class="flex border-2 border-b-grau2">
<img v-if="self_id != '99' " src="../../assets/default_pp.png" alt="" class="rounded-full w-16 h-16">
<img v-else src="../../assets/danielvici_pp.png" alt="" class="rounded-full w-16 h-16">
<form class="w-full pr-5">
<img src="../../assets/danielvici_pp.png" alt="" class="p-2 rounded-full w-16 h-16">
<form>
<!-- post_publish ist richtig aber wird falsch angezeigt. File Input geht nicht-->
<textarea v-model="post_create_text" name="post_text" class="bg-hintergrund-farbe rounded-lg m-2 p-1 focus:outline-none text-grau2 w-full resize-none" rows="3" placeholder="Write something..."></textarea>
<textarea v-model="post_publish" name="post_text" class="bg-hintergrund-farbe rounded-lg m-2 p-1 focus:outline-none text-grau2 w-200p resize-none" rows="3" placeholder="Write something..."></textarea>
<div class="">
<button id="post_publish" name="post_publishss" class="text-weiss p-1 m-2 rounded-lg py-3 px-5 bg-button-farbe" @click.prevent="post_create(post_create_text)" type="button">Post</button>
<input class="text-weiss" type="file" accept=".png, .jpg, .jpeg">
<button id="post_publish" name="post_publishss" class="text-weiss p-1 m-2 rounded-lg py-3 px-5 bg-button-farbe" @click.prevent="post_publish_func(post_publish)" type="button">Post</button>
</div>
</form>
</form>
</div>
</div>
<div class="sm:overflow-y-auto sm:h-[650px] sm:scrollbar"> <!-- CONTENT -->
<ul>
<li v-for="(postitem, indexus) in upc" :key="upc" class="border-2 border-b-grau2 p-3 flex">
<!-- POST -->
<img v-if="postitem.username != 'danielvici' " src="../../assets/default_pp.png" alt="" class="rounded-full w-16 h-16">
<img v-else src="../../assets/danielvici_pp.png" alt="" class="rounded-full w-16 h-16">
<div> <!-- CONTENT -->
<ul>
<li v-for="(postitem, indexus) in post" :key="post" class="border-2 border-b-grau2 p-3 flex">
<!-- POST -->
<img src="../../assets/default_pp.png" alt="" class="rounded-full w-16 h-16">
<div>
<div> <!-- POST HEADER -->
<label class="text-lg font-bold m-1 text-weiss">{{postitem.displayname}}</label>
<label class="text-base m-1 text-grau2">@{{ postitem.username }}</label>
<label class="text-lg font-bold m-1 text-weiss">{{postitem.author_display_name}}</label>
<label class="text-base m-1 underline-offset-3 text-grau2">@{{ postitem.author_username }}</label>
</div>
<div class="m-2"> <!-- POST CONTENT -->
<p class="text-sm m-1 text-weiss">{{ postitem.post_text }}</p>
<p class="text-sm m-1 text-weiss">{{ postitem.content }}</p>
</div>
<div class="sm:flex"><!-- POST FOOTER -->
<div class="flex">
<div class="flex"> <!-- Comments -->
<img src="../../assets/icons/comment.png" alt="" class="rounded-full align-middle">
<label class="text-sm m-1 text-weiss" v-if="postitem.comments != undefined">{{ postitem.comments }}</label>
<label class="text-sm m-1 text-weiss" v-else>Comments disabled</label>
</div>
<div class="flex items-center" @click="addLike(postitem.post_id, postitem.user_id, indexus)"> <!-- Likes -->
<img alt="" src="../../assets/icons/herz.png" class="align-middle">
<label class="text-sm m-1 text-weiss">{{ postitem.likes }}</label>
</div>
<div class="flex"> <!-- POST FOOTER -->
<div class="flex"> <!-- Comments -->
<img src="../../assets/icons/comment.png" alt="" class="rounded-full align-middle">
<label class="text-sm m-1 text-weiss" v-if="postitem.comments_count != undefined">{{ postitem.comments_count }}</label>
<label class="text-sm m-1 text-weiss" v-else>Comments disabled</label>
</div>
<br class="sm:hidden">
<div class="flex sm:tems-center mx-2"> <!-- View Post -->
<button @click="gotoPost(postitem.post_id)" class="text-schwarz mx-1 px-1 rounded-lg bg-button-farbe">View Post</button>
<button @click="copyLink(postitem.post_id)" class="text-schwarz pl-1 mx-1 px-1 rounded-lg bg-button-farbe">Share Post</button>
<button @click="gotoProfile(postitem.user_id)" class="text-schwarz pl-1 mx-1 px-1 rounded-lg bg-button-farbe"> Go to Profile</button>
<div class="flex items-center" @click="addLike(indexus)"> <!-- Likes -->
<img alt="" src="../../assets/icons/herz.png" class="align-middle">
<label class="text-sm m-1 text-weiss">{{ postitem.likes }}</label>
</div><!-- ENDE -->
</div>
</div>

View File

@@ -1,32 +1,18 @@
<script setup lang="ts">
import {useRoute, useRouter} from "vue-router";
const route = useRoute();
const router = useRouter();
function gotop() {
location.reload();
console.log("PARAMS: "+ route.path);
console.log("Zum Seitenanfang gescrollt");
}
</script>
<template>
<div class="text-grau2 p-3 text-center">
<div class="text-grau2 p-3">
<a href="">Terms of Service</a>
-
<a href="">Privacy Policy</a><br>
<a href="">Imprint</a>
-
<a href="https://esp-projekt.notion.site/191fb990f26c808298dad302e97fb299?pvs=105">Contact</a>
<a href="">Contact</a>
-
<a href="https://esp-projekt.notion.site/191fb990f26c808298dad302e97fb299?pvs=105">Support</a>
-
<a href="https://icons8.com"> Icons by icons8.com</a>
<div class="sm:hidden flex justify-center pt-8"><button class="text-weiss p-1 m-2 rounded-lg py-3 px-5 bg-button-farbe transition duration-300 ease-in-out" @click="gotop">Back to Top</button></div>
<a href="">Support</a>
</div>
</template>

View File

@@ -1,74 +1,43 @@
<script setup lang="ts">
// Funktionen um die Seiten zu öffnen
// home -> app.vue
// PLACEHOLDER
import router from "../../router";
import { ref, onMounted, onUnmounted } from 'vue';
let self;
const isMobile = ref(false);
const show = ref(false);
const sb_home = () => {
console.log("home");
router.push("/");
}
const sb_search = () => {
console.log("Search");
}
const sb_notifications = () => {
console.log("Notifications");
}
const sb_messages = () => {
console.log("Messages");
}
const sb_accounts = () => {
console.log("Accounts");
}
const sb_settings = () => {
console.log("Settings");
}
const getShowMobileElements = () => {
const value = localStorage.getItem("mobile");
console.log("localStorage mobile:", value); // Debugging-Ausgabe
return value === 'true';
};
const setShowMobileElements = (value) => {
console.log("localStorage set mobile:", value.toString()); // Debugging-Ausgabe
localStorage.setItem("mobile", value.toString());
};
const toggleElements = () => {
if (isMobile.value){
show.value = !show.value;
setShowMobileElements(show.value);
}
};
const checkScreenWidth = () => {
isMobile.value = window.innerWidth < 640;
if(isMobile.value === false){
show.value = true;
} else {
show.value = false;
}
};
onMounted(() => {
checkScreenWidth();
window.addEventListener('resize', checkScreenWidth);
const show = ref(getShowMobileElements());
if(localStorage.getItem("mobile") === null){
show.value = false;
}
self = localStorage.getItem("self_id");
console.log("SELF NB: " + self);
});
onUnmounted(() => {
window.removeEventListener('resize', checkScreenWidth);
});
</script>
<template>
<div class="pt-4 border-b-2 border-b-grau2">
<div class="items-center flex justify-center"><!-- BILD-->
<img src="../../assets/esp-logo_no_text.png" alt="" class="rounded-lg h-12 w-24 mx-auto hover:shadow-2xl hover:shadow-grau-dunkel" @click="router.push('/')">
<div class="items-center flex justify-center">
<img src="../../assets/esp-logo_no_text.png" alt="" class="rounded-lg h-12 w-24 mx-auto" @click="sb_home">
</div>
<div class="sm:hidden text-weiss items-center flex justify-center mt-2 py-4 border-y-2 border-y-grau2 " v-if="isMobile">
<button @click="toggleElements"> {{ show ? 'close navbar' : 'expand navbar' }} </button>
</div>
<div class="align-middle space-y-3 pt-4 pl-3 pb-4 pr-4 font-bold text-xl" v-if="show || !isMobile"> <!-- Icons (Bild) und Text Damit der Text weiß ist muss zwei mal gedrückt werden manchmal-->
<label class="flex text-center text-grau2 hover:bg-logo-farbe-lila rounded-lg" @click="router.push('/')"><img class="mr-2 p-1 bg-logo-farbe-lila rounded-lg" src="../../assets/icons/home.png" alt=""> Home</label>
<label class="flex text-center text-grau2 hover:bg-logo-farbe-lila rounded-lg" @click="router.push('/search')"> <img class="mr-2 p-1 bg-logo-farbe-lila rounded-lg" src="../../assets/icons/lupe.png" alt="">Search</label>
<label class="flex text-center text-grau2 hover:bg-logo-farbe-rot rounded-lg" @click="router.push('/notifications')"> <img class="mr-2 p-1 bg-logo-farbe-rot rounded-lg" src="../../assets/icons/glocke.png" alt="">Notifications</label>
<label class="flex text-center text-grau2 hover:bg-logo-farbe-rot rounded-lg" @click="router.push('/messages')"> <img class="mr-2 p-1 bg-logo-farbe-rot rounded-lg" src="../../assets/icons/mail.png" alt="">Messages</label>
<label class="flex text-center text-grau2 hover:bg-logo-farbe-blau rounded-lg" @click="router.push(`/profile/${self}`)"> <img class="mr-2 p-1 bg-logo-farbe-blau rounded-lg" src="../../assets/icons/user.png" alt="">Profile</label>
<label class="flex text-center text-grau2 hover:bg-logo-farbe-blau rounded-lg" @click="router.push('/settings')"> <img class="mr-2 p-1 bg-logo-farbe-blau rounded-lg" src="../../assets/icons/zahnrad.png" alt="">Settings</label>
<div class="align-middle space-y-3 pt-3 pl-3 pb-4 font-bold text-xl">
<label class="flex text-center text-grau2 hover:bg-logo-farbe-lila shadow-2xl rounded-lg" @click="sb_home"><img class="pr-2" src="../../assets/icons/home.png" alt=""> Home</label>
<label class="flex text-center text-grau2 hover:bg-logo-farbe-lila shadow-2xl rounded-lg" @click="sb_search"><img class="pr-2" src="../../assets/icons/lupe.png" alt="">Search</label>
<label class="flex text-center text-grau2 hover:bg-logo-farbe-rot shadow-2xl rounded-lg" @click="sb_notifications"><img class="pr-2" src="../../assets/icons/glocke.png" alt="">Notifications</label>
<label class="flex text-center text-grau2 hover:bg-logo-farbe-rot shadow-2xl rounded-lg" @click="sb_messages"><img class="pr-2" src="../../assets/icons/mail.png" alt="">Messages</label>
<label class="flex text-center text-grau2 hover:bg-logo-farbe-blau shadow-2xl rounded-lg" @click="sb_accounts"><img class="pr-2" src="../../assets/icons/user.png" alt="">Profile</label>
<label class="flex text-center text-grau2 hover:bg-logo-farbe-blau shadow-2xl rounded-lg" @click="sb_settings"><img class="pr-2" src="../../assets/icons/zahnrad.png" alt="">Settings</label>
</div>
</div>
</template>

View File

@@ -1,112 +0,0 @@
<script setup lang="ts">
import {defineProps, defineEmits, onMounted, watch, ref} from 'vue';
import { nextTick } from 'vue';
let current_contact = null;
let self = "danielvici123";
const nachrichten = [
{ display_name: "Linux Enjoyer", username: "lunix", message: "Moin", msg_id: 1, chat_id: 16423 },
{ display_name: "XBOX",username: "xbox", message: "Hey, was geht?", msg_id: 2, chat_id: 29874 },
{ display_name: "danielvici223", username: "danielvici123", message: "Alles gut, und bei dir?", msg_id: 3, chat_id: 29874 },
{ display_name: "JETBrains",username: "jetbrains", message: "Hat jemand Erfahrung mit IntelliJ?", msg_id: 4, chat_id: 41235 },
{ display_name: "danielvici223",username: "danielvici123", message: "Ja, was brauchst du?", msg_id: 5, chat_id: 41235 },
{ display_name: "JETBrains",username: "jetbrains", message: "Wie kann ich Plugins effizient verwalten?", msg_id: 6, chat_id: 41235 },
{ display_name: "klopupser13", username: "theopampa", message: "ja ok können wir machen", msg_id: 7, chat_id: 41245 },
{ display_name: "danielvici223",username: "danielvici123", message: "willst du fornite", msg_id: 7, chat_id: 41245 },
];
let geladeneNachrichten = ref([]);
const send_message = ref("");
const props = defineProps({
contact: Object
});
const emit = defineEmits(['close']);
function closeChat() {
emit('close');
}
function openCHAT() {
geladeneNachrichten.value = [];
console.log("Chat geöffnet");
// conact ist null dann abruch
if(!props.contact) return;
// contact ist der aktuelle kontakt
current_contact = props.contact ? { ...props.contact } : null;
console.log(current_contact);
/*nachrichten.forEach((nachricht) => {
if ((nachricht.username == current_contact.username || nachricht.username == self) && nachricht.chat_id == current_contact.chat_id) {
geladeneNachrichten.value.push(nachricht);
}
});
*/
geladeneNachrichten.value = nachrichten.filter((nachricht) => {
console.log(`Nachricht von ${nachricht.username} mit Chat-ID ${nachricht.chat_id}`);
return (
(nachricht.username === current_contact.username || nachricht.username === self) &&
nachricht.chat_id == current_contact.chat_id
);
});
console.log("Nach dem Filtern:", geladeneNachrichten.value);
console.log(geladeneNachrichten);
}
function sendMessage(event){
event.preventDefault();
// API nachricht senden
console.log("Nachricht gesendet")
}
onMounted(() => {
openCHAT();
console.log("Current Contact:", current_contact);
});
watch(() => props.contact, () => {
openCHAT();
console.log("Current Contact:", current_contact);
});
</script>
<template>
<div class="fixed bottom-0 right-0 m-3 p-4 bg-schwarz text-weiss rounded-lg shadow-lg w-80">
<div class="flex justify-between items-center bborder-b-2 border-b-grau2">
<div class="flex">
<h3 class="text-lg font-bold">{{ contact.display_name }}</h3>
<a class="px-2">@{{ contact.username }}</a>
</div>
<button @click="closeChat"><img src="../../assets/icons/x-klein.png" alt=""></button>
</div>
<div class="mt-2">
<ul class="space-y-2">
<li v-for="(msg) in geladeneNachrichten" :key="msg.msg_id || msg.id">
<div class="space-x-2">
<a class="font-bold">{{ msg.display_name }}</a>
</div>
<div>
<p>{{ msg.message }}</p>
</div>
</li>
</ul>
<div>
<form class="flex mt-4" @submit="sendMessage">
<label><input v-model="send_message" class="bg-schwarz outline-none border-b-2 mt-2 py-2 px-1" placeholder="Message"></label>
<button type="submit"><img src="../../assets/icons/send.png" alt="senden" class="ml-4 mt-1"></button>
</form>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,16 @@
<script setup>
</script>
<template>
<div class="flex p-4 border-b-2 border-b-grau2 ">
<div class="w-12">
<img class="p-2 bg-grau rounded-l-lg" src="../../assets/icons/lupe.png" alt="">
</div>
<input type="text" class="bg-grau rounded-r-lg focus:outline-none text-weiss" placeholder="Search...">
</div>
</template>
<style scoped>
</style>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
// PLACEHOLDER
const hashtags = [
{id: 1,name: "xbox", nr_posts: 553,category: "Gaming" } ,
{id: 2,name: "lol" , nr_posts: 16422, category: "Gaming"},

View File

@@ -1,76 +1,21 @@
<script setup lang="ts">
import router from "../../router";
import { ref, onMounted } from 'vue';
<script setup>
let input_username_mail = ref("");
let input_user_password = ref("");
let rememberMe = ref(false);
onMounted(() => {
if (localStorage.getItem('username')) {
input_username_mail.value = localStorage.getItem('username') || "";
input_user_password.value = localStorage.getItem('password') || "";
rememberMe.value = false;
}
});
async function login(event: Event) {
event.preventDefault();
const username = input_username_mail;
const password = input_user_password;
if (username.value === "" || password.value === "") {
alert("Please fill all fields");
return;
}
try {
const response = await fetch('http://localhost:8000/api/account/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username: username.value, password: password.value }),
});
if (response.status === 200) {
const data = await response.json();
localStorage.setItem('isLoggedIn', 'true');
localStorage.setItem('username', username.value);
localStorage.setItem('self_id', data["userId"]);
console.log("SELF LOG: " + data["userId"]);
alert("You will be now redirected");
router.push('/');
} else {
alert("Username/E-Mail or Password are wrong");
}
} catch (e) {
console.log("An error has occurred. Please try again later.");
console.log(e)
}
}
</script>
<template>
<div class="px-20 sm:border-x sm:border-x-grau2 pb-32">
<div class="text-3xl pt-32"> <!-- ÜBERSCHRIFT-->
<p class="text-weiss text-center">Welcome to <label class="bg-schwarz p-1 rounded-lg mr-1"><span class="text-logo-farbe-lila">E</span><span class="text-logo-farbe-rot">S</span><span class="text-logo-farbe-blau">P</span></label>!</p>
<p class="text-weiss text-center">Login to continue</p>
<div class="px-20 border-x border-x-grau2 pb-35p">
<div class="text-3xl pt-32">
<p class="text-weiss text-center">Welcome to <span class="text-button-farbe">ESP</span>!</p>
<p class="text-weiss text-center">Login or create a new Account to continue</p>
</div>
<div class="px-20 pt-7"><!-- FORM --->
<form class="flex flex-col items-center" @submit.prevent="login">
<input class="m-4 md:w-full md:max-w-xs bg-grau-dunkel p-4 text-weiss placeholder-grau2 focus:outline-none rounded-lg" v-model="input_username_mail" type="text" placeholder="Username or E-Mail"><br>
<input class="m-4 md:w-full md:max-w-xs bg-grau-dunkel p-4 text-weiss placeholder-grau2 focus:outline-none rounded-lg" v-model="input_user_password" type="password" placeholder="Password"><br>
<button class="m-4 bg-button-farbe w-full md:max-w-xs p-4 text-schwarz rounded-lg">Login</button>
<div class="px-20 pt-7">
<form class="flex flex-col items-center">
<input class="m-4 w-full max-w-xs bg-grau-dunkel p-4 text-weiss placeholder-grau2 focus:outline-none rounded-lg" type="text" placeholder="Username or E-Mail"><br>
<input class="m-4 w-full max-w-xs bg-grau-dunkel p-4 text-weiss placeholder-grau2 focus:outline-none rounded-lg" type="text" placeholder="Password"><br>
<button class="m-4 bg-grau-dunkel w-full max-w-xs p-4 text-weiss rounded-lg">Login</button>
</form>
</div>
<div>
<p class="text-weiss text-center pb-2 ">No Account? <router-link to="/register" class="text-button-farbe">Register here</router-link></p>
<p class="text-weiss text-center pt-2"> <router-link to="/wip" class="text-button-farbe">Forgot password?</router-link> </p>
</div>
</div>
</template>
<style scoped>

View File

@@ -1,27 +0,0 @@
<script setup>
import Contacts from "./home_components/contacts.vue";
import Feed from "./home_components/feed.vue";
import Legal from "./home_components/legal.vue";
import Navigationbar from "./home_components/navigationbar.vue";
import Msg_main from "./messages_components/msg_main.vue";
</script>
<template>
<div id="main" class=" sm:flex">
<div id="left" class="sm:w-72 min-w-72">
<navigationbar></navigationbar>
</div>
<div class="w-100p">
<msg_main></msg_main>
</div>
<div class="sm:w-1/4">
<contacts></contacts>
<legal></legal>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,60 +0,0 @@
<script setup lang="ts">
import {ref} from "vue";
import Popup_chat from "../home_components/popup_chat.vue";
const nachrichten = ref([
{id: 1,
profile_picture: "../../assets/default_pp.png", display_name: "Linux Enjoyer",username: "lunix",
content:"Moin!",
type:"message",date: new Date(2024,11,13).toDateString() },
{id: 2,
profile_picture: "../../assets/default_pp.png",
display_name: "XBOX",username: "xbox",
content: "Hey, was geht?",
type:"message",date: new Date(2024,9,13).toDateString()},
{id: 4,// Sollte im feed sein
profile_picture: "../../assets/default_pp.png",
display_name: "klopupser13", username: "theopampa",
content: "ja ok können wir machen",
type:"following",date: new Date(2025,1,15).toDateString()}
]);
const selectedContact = ref(null);
const showChatPopup = ref(false);
function openChat(contact) {
selectedContact.value = contact;
showChatPopup.value = true;
}
</script>
<template>
<div class="border-x-grau2 border-x-2">
<div class="border-b-grau2 border-b-2">
<h1 class="text-weiss text-3xl p-4">Messages</h1>
</div>
<div>
<ul>
<li v-for="nachricht in nachrichten" :key="nachricht.id" class="border-b-grau2 border-b-2" @click="openChat(nachricht)">
<div class="flex p-4">
<img src="../../assets/default_pp.png" alt="user profile picture" class="rounded-full w-16 h-16">
<div>
<div class="flex mb-1">
<label class="text-lg font-bold sm:m-1 ml-1 text-weiss">{{nachricht.display_name}}</label>
<label class="text-lg sm:m-1 ml-1 text-grau2">@{{nachricht.username}}</label>
<label class="sm:m-2 ml-1 text-grau2">{{nachricht.date}}</label>
</div>
<a class="ml-1 text-weiss">{{nachricht.content}}</a>
</div>
</div>
</li>
</ul>
</div>
<popup_chat v-if="showChatPopup" :contact="selectedContact" @close="showChatPopup = false" />
</div>
</template>
<style scoped>
</style>

View File

@@ -1,26 +0,0 @@
<script setup>
import Legal from "./home_components/legal.vue";
import Navigationbar from "./home_components/navigationbar.vue";
import Notifi_comp from "./notifications_components/notifi_main.vue";
import Contacts from "./home_components/contacts.vue";
</script>
<template>
<div class="text-weiss sm:flex">
<div id="left" class="border-1 border-b-grau sm:w-72 min-w-72">
<navigationbar></navigationbar>
</div>
<div class="w-100p border-x-2 border-x-grau2">
<notifi_comp></notifi_comp>
</div>
<div class="sm:w-1/4">
<contacts></contacts>
<legal></legal>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,124 +0,0 @@
<script setup lang="ts">
console.log("SEITE WIRD AUSGEFÜHRT")
import {ref} from "vue";
const notifications = ref([
{id: 1, // Sollte im feed sein
profile_picture: "../../assets/default_pp.png",
author_display_name: "Linux Enjoyer",author_username: "lunix",
content:"I love Linux. My Favorite Linux Distro is ARCH LINUX.",
type:"message",date: new Date(2024,11,13).toDateString() }, // 11 = Dezember, 10 = Nov, 9 = okt., 8 = sep.
{id: 2,
profile_picture: "../../assets/default_pp.png",
author_display_name: "XBOX",author_username: "Xbox",
content: "Call of Duty: Black Ops 6 is OUT NOW. Check it out: https://xbox.com",
type:"message",date: new Date(2024,9,13).toDateString()},
{id: 33,// Sollte im feed sein
profile_picture: "../../assets/default_pp.png",
author_display_name: "ESP Support",author_username: "esp_support",
content: "You're post was against our TOS and got deleted. Additionally your account has been suspended for 30 Days." ,
type:"support",date: new Date(2024,9,13).toDateString()},
{id: 4,// Sollte im feed sein
profile_picture: "../../assets/default_pp.png",
author_display_name: "System", author_username: "esp_notifications",
content: "GitHub posted something new. Check it out",
type:"following",date: new Date(2024,10,2).toDateString()},
{id: 5, // Sollte im feed sein
profile_picture: "../../assets/danielvici_pp.png",
author_display_name: "danielvici123", author_username: "danielvici",
content: "I created this WebApp with VUE3 and TailwindCSS. It was a lot of fun.",
type:"message",date: new Date(2024,1,1).toDateString()}
]);
let feed = ref([]);
// wie enum in c bzw. arduino
interface sortting_definition {
f: boolean; // following
m: boolean; // messages
da: boolean; // date-asc
dd: boolean; // date-desc
u: boolean; // user
sorting: string;
}
// Standard filter und sorting
const check_type = ref<sortting_definition>({
f: true,
m: true,
da: false,
dd: false,
u: false,
sorting: "date-asc",
});
// Für jeden eintrag in notifications durschläuft die schleife einen durschlauf
for(let i =0; i < notifications.value.length; i++) {
console.log("Getting Notifications...");
feed.value.push(notifications.value[i]);
}
function go_filter(){
console.log("Filter applied");
console.log("These Filter applied: ", JSON.stringify(check_type.value));
feed.value = [];
notifications.value.forEach((notification) => {
if ((check_type.value.f == true && notification.type === "following") || (check_type.value.m == true && notification.type === "message")|| (notification.type === "support")){
feed.value.push(notification);
}
})
console.log("Feed:", feed.value);
}
</script>
<template>
<div>
<div class="border-b-grau2 border-b-2">
<h1 class="text-weiss text-3xl p-4">Notifications</h1>
</div>
<div class="text-grau2 p-5 border-b-2 "><!-- FILTER -->
<!-- Wenn das Form submited wurde wird die Seite nicht-->
<!-- neugeladen und die Funktion -->
<form @submit.prevent="go_filter">
<label class="p-2 text-xl text-weiss">Filter</label>
<label class="m-2 accent-logo-farbe-blau">You Following<input type="checkbox" class="m-1 mr-3" v-model="check_type.f"></label>
<label class="m-2 accent-logo-farbe-rot">Messages<input type="checkbox" class="m-1 mr-3" v-model="check_type.m"></label>
<!--<label class="m-2 accent-logo-farbe-rot">Other<input type="checkbox" class="m-1 mr-3" v-model="check_type.o"></label>-->
<label class="p2">Sort by <select name="sorting" id="notification_sorting" class="mr-3 bg-hintergrund-farbe text-weiss" v-model="check_type.sorting">
<option value="date-asc">Date (asc.)</option>
<option value="date-desc">Date (desc.)</option>
<option value="user">User</option>
</select></label>
<button type="submit" class="bg-button-farbe text-schwarz p-2 rounded-lg">Filter</button>
</form>
</div>
<div> <!-- MAIN NACHRICHTEN-->
<ul v-if="feed.length > 0">
<li v-for="(notification) in feed" :key="notifications.id" class="border-b-grau2 border-b-1 border-b p-3 flex">
<img src="../../assets/default_pp.png" alt="user profile picture" class="rounded-full w-16 h-16">
<div>
<div class="flex">
<label class="text-lg font-bold m-1 text-weiss">{{notification.author_display_name}}</label>
<label class="m-2 text-grau2">Type: {{notification.type}}</label>
<label class="m-2 text-grau2">Date: {{notification.date}}</label>
</div>
<a class="ml-1">{{notification.content}}</a>
</div>
</li>
</ul>
<a v-else>You have no Notifications!</a>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,327 +0,0 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import {useRoute, useRouter} from 'vue-router';
import Navigationbar from './home_components/navigationbar.vue';
import Contacts from './home_components/contacts.vue';
import Legal from './home_components/legal.vue';
interface Post {
post_uuid: number;
user_id: number;
author_username: string;
post_text: string;
likes: number;
comments_count: number;
comments: any[];
created_at: string;
}
interface User {
user_id: number;
username: string;
displayname: string;
}
interface Comment {
comment_id: number;
author_user_id: number;
post_id: number;
text: string;
likes: number;
created_at: string;
displayname: string;
username: string;
}
const route = useRoute();
const router = useRouter();
const post = ref<Post | null>(null);
const user = ref<User | null>(null);
const comments = ref<Comment[] | null>(null);
let comment_text = ref();
let self_id;
const loading = ref(true);
let post_uuid = ref();
async function getPost(post_id: any) {
try {
const post_response = await fetch(`http://localhost:8000/api/post/${post_id}`, {method: 'GET'});
const fetchedPost: Post = await post_response.json();
if (post_response.status === 404) {
console.error("No comments found.");
alert("Post not found")
await router.push('/');
return;
}
const user_response = await fetch('http://localhost:8000/api/users', {method: 'GET'});
const usersDATA = await user_response.json();
const postAuthor = usersDATA.find(user => user.user_id === fetchedPost.user_id);
if (postAuthor) {
console.log("The post was written by:", postAuthor);
} else {
console.error("Author not found.");
}
user.value = postAuthor;
post.value = fetchedPost;
console.log(post.value);
} catch (e) {
console.error(e);
} finally {
loading.value = false;
}
}
async function getComment(post_id: any) {
try {
const comments_response = await fetch(`http://localhost:8000/api/post/${post_id}/comments`, { method: 'GET' });
const fetchedComments: Comment[] = await comments_response.json();
const user_response = await fetch(`http://localhost:8000/api/users`, { method: 'GET' });
const usersDATA: User[] = await user_response.json();
if(comments_response.status === 404 || user_response.status === 404) {
console.error("ERRROR");
alert("Error try it again later.");
await router.push('/');
return;
}
comments.value = fetchedComments.map(comment => {
const author = usersDATA.find(u => u.user_id === comment.author_user_id) || {
username: 'Unknown',
displayname: 'Unknown',
};
return {
...comment,
username: author.username,
displayname: author.displayname,
};
});
comments.value.sort((a, b) => b.post_id - a.post_id);
console.log(comments.value);
} catch (e) {
console.error(e);
}
}
function copyLink(post_id: string | number) {
const tocopy = `http://localhost:5173/post/${post_id}`;
navigator.clipboard.writeText(tocopy);
alert("Copied to clipboard");
}
async function addLike() { // Post liken
try {
post.value.likes++;
const response_like = await fetch(`http://localhost:8000/api/post/${post_uuid.value}/like`, {
method: 'POST',
headers: {'content-type': 'application/json'},
body: `{"userId":${self_id}}`,
});
if(response_like.status === 404) {
console.error("ERROR");
await router.push('/');
return;
}
const data = await response_like.json();
console.log("post_id 2: ", post_uuid);
return data;
} catch (error) {
console.error('Fehler beim Liken des Posts:', error);
throw error;
}
}
async function comment_create_text(comment_text: string) {
if (comment_text === null) {
alert("Please write something before commenting.");
return;
}
try {
const response = await fetch(`http://localhost:8000/api/post/${post_uuid.value}/comment`, {
method: 'POST',
headers: {'content-type': 'application/json'},
body: `{"userId":${self_id},"text":"${comment_text}"}`,});
const data = await response.json();
if(response.status === 404) {
console.error("ERROR");
await router.push('/');
return;
}
await getComment(parseInt(post_uuid.value));
return data;
} catch (error) {
console.error(error);
}
console.log(comment_text);
}
async function addLike_comment(comment_id: number | string) {
try {
post.value.likes++;
const response_like = await fetch(`http://localhost:8000/api/comment/${comment_id}/like`, {
method: 'POST',
headers: {'content-type': 'application/json'},
body: `{"userId":${self_id}}`,
});
if(response_like.status === 404) {
console.error("ERROR");
await router.push('/');
return;
}
const data = await response_like.json();
console.log("post_id: ", comment_id);
console.log(data);
getComment(parseInt(post_uuid.value));
return data;
} catch (error) {
console.error('Fehler beim Liken des Posts:', error);
throw error;
}
}
function gotoProfile(user_id: string | number) {
router.push(`/profile/${user_id}`);
}
onMounted(async () => {
console.log("PARAMS: "+ route.path);
const pathArray = route.path.split('/');
console.log(pathArray);
if (pathArray.length > 2) {
post_uuid.value = pathArray[2];
console.log("post_id 0: ", post_uuid.value);
}
if (!post_uuid) {
alert('No post selected. Redirecting to feed.');
await router.push('/');
return;
}
self_id = localStorage.getItem('self_id');
getPost(parseInt(post_uuid.value));
getComment(parseInt(post_uuid.value));
});
</script>
<template>
<div id="main" class="bg-hintergrund-farbe sm:flex overflow-y-auto sm:h-full sm:scrollbar">
<div id="left" class="sm:w-72 min-w-72">
<navigationbar></navigationbar>
</div>
<div class="text-weiss sm:w-100p w-screen sm:border-x sm:border-x-grau2" v-if="post">
<div> <!-- HEADER -->
<h2 class="align-middle p-6 text-3xl text-weiss border-b-grau2 border-b">Post</h2>
</div>
<div class="flex px-2 py-4 border-b-grau2 border-b">
<img v-if="user.username != 'danielvici' " src="../assets/default_pp.png" alt="" class="rounded-full w-16 h-16">
<img v-else src="../assets/danielvici_pp.png" alt="" class="rounded-full w-16 h-16">
<div>
<div> <!-- POST HEADER -->
<label class="text-lg font-bold m-1 text-weiss">{{user.displayname}}</label>
<label class="text-base m-1 text-grau2">@{{ user.username }} | </label>
<label class="text-base text-grau2"> Posted at {{ post.created_at }}</label>
</div>
<div class="m-2"> <!-- POST CONTENT -->
<p class="text-sm m-1 text-weiss">{{ post.post_text }}</p>
</div>
<div class="flex"> <!-- POST FOOTER -->
<div class="flex"> <!-- Comments -->
<img src="../assets/icons/comment.png" alt="" class="rounded-full align-middle">
<label class="text-sm m-1 text-weiss" v-if="post.comments != undefined">{{ post.comments }}</label>
<label class="text-sm m-1 text-weiss" v-else>Comments disabled</label>
</div>
<div class="flex items-center" @click="addLike()"> <!-- Likes -->
<img alt="" src="../assets/icons/herz.png" class="align-middle">
<label class="text-sm m-1 text-weiss">{{ post.likes }}</label>
</div>
<button @click="copyLink(post_uuid)" class="text-schwarz pl-1 mx-1 px-1 rounded-lg bg-button-farbe">Share Post</button>
</div>
</div>
</div>
<div> <!-- COMMENTS VIEW and WRITE -->
<div>
<h2 class="align-middle p-6 text-xl text-weiss border-b-grau2 border-b">Comments</h2>
</div>
<div> <!-- WRITE COMMENTS -->
<div class="flex border-b-2 border-b-grau2">
<img v-if="self_id != '99' " src="../assets/default_pp.png" alt="" class="p-2 rounded-full w-16 h-16">
<img v-else src="../assets/danielvici_pp.png" alt="" class="p-2 rounded-full w-16 h-16">
<!-- <img src="../assets/danielvici_pp.png" alt="" class="p-2 rounded-full w-16 h-16">-->
<form class="w-full pr-5">
<!-- post_publish ist richtig aber wird falsch angezeigt. File Input geht nicht-->
<textarea v-model="comment_text" name="post_text" class="bg-hintergrund-farbe rounded-lg m-2 p-1 focus:outline-none text-grau2 w-full resize-none" rows="3" placeholder="Write something..."></textarea>
<div class="">
<button id="post_publish" name="post_publishss" class="text-weiss p-1 m-2 rounded-lg py-3 px-5 bg-button-farbe" @click.prevent="comment_create_text(comment_text)" type="button">Post</button>
</div>
</form>
</div>
</div>
<div> <!-- VIEW COMMENTS -->
<div class="sm:overflow-y-scroll h-[450px]"> <!-- VIEW COMMENTS -->
<ul v-if="comments && comments.length > 0">
<li v-for="c in comments" :key="c.comment_id" class="p-4 border-b border-gray-700">
<div class="flex">
<img v-if="c.author_user_id != '99' " src="../assets/default_pp.png" alt="" class="p-2 rounded-full w-16 h-16">
<img v-else src="../assets/danielvici_pp.png" alt="" class="p-2 rounded-full w-16 h-16">
<div>
<div> <!-- POST HEADER -->
<label class="text-lg font-bold m-1 text-weiss">{{c.displayname}}</label>
<label class="text-base m-1 text-grau2">@{{ c.username }}</label>
</div>
<div class="m-2"> <!-- POST CONTENT -->
<p class="text-sm m-1 text-weiss">{{ c.text }}</p>
</div>
<div class="flex"> <!-- POST FOOTER -->
<div class="flex items-center" @click="addLike_comment(c.comment_id)"> <!-- Likes -->
<img alt="" src="../assets/icons/herz.png" class="align-middle">
<label class="text-sm m-1 text-weiss">{{ c.likes }}</label>
</div>
</div>
</div>
</div>
</li>
</ul>
<div v-else class="p-4 text-gray-400">No comments yet.</div>
</div>
</div>
</div>
</div>
<div class="sm:w-1/4 w-screen">
<contacts></contacts>
<legal></legal>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,26 +0,0 @@
<script setup>
import Navigationbar from "./home_components/navigationbar.vue";
import Contacts from "./home_components/contacts.vue";
import Legal from "./home_components/legal.vue";
import Profile_main from "./profile_components/profile_main.vue";
</script>
<template>
<div id="main" class="bg-hintergrund-farbe sm:flex overflow-visible scrollbar sm:overflow-y-auto sm:h-full sm:scrollbar">
<div id="left" class="sm:w-72 min-w-72">
<navigationbar></navigationbar>
</div>
<div class="sm:w-100p w-screen sm:border-x sm:border-x-grau2">
<profile_main></profile_main>
</div>
<div id="right" class="sm:w-1/4 w-screen">
<contacts></contacts>
<legal></legal>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,205 +0,0 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
const route = useRoute();
const router = useRouter();
const upc = ref([]);
const profile_id = ref<number | null>(null);
const userData = ref<any>(null);
onMounted(async () => {
const pathArray = route.path.split('/');
if (pathArray.length > 2) {
profile_id.value = parseInt(pathArray[2], 10);
} else {
console.warn("No profile ID found in the route.");
}
if (!profile_id.value) {
alert('No profile selected. Redirecting to feed.');
await router.push('/');
return;
}
await create_own_posts();
await getUser();
});
async function create_own_posts() {
try {
const post_response = await fetch('http://localhost:8000/api/posts', {
method: 'GET',
});
if (!post_response.ok) {
throw new Error(`HTTP error! status: ${post_response.status}`);
}
const postsDATA = await post_response.json();
upc.value = postsDATA.filter((post) => post.user_id === profile_id.value);
if (upc.value.length === 0) {
console.warn('No posts found for this user.');
return;
}
//console.log("upc: "+ JSON.stringify(upc.value, null, 2));
return upc.value;
} catch (error) {
console.error('Error fetching posts:', error);
upc.value = [];
}
}
async function addLike(post_id: string | number, user_id: number, index: number) {
try {
upc.value[index].likes++;
const response = await fetch(`http://localhost:8000/api/post/${post_id}/like`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: `{"userId":${user_id}}`,
});
if (!response.ok) {
const errorText = await response.text();
console.error('Server-Fehlertext:', errorText);
throw new Error(`HTTP error! status: ${response.status}, text: ${errorText}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Fehler beim Liken des Posts:', error);
throw error;
}
}
function consoleLog() {
console.log("upc: ", upc.value);
console.log("profile_id: ", profile_id.value);
}
function gotoPost(post_id: string | number) {
localStorage.setItem("viewedpost", post_id.toString());
router.push(`/post/${post_id}`);
}
function copyLink(post_id: string | number) {
const tocopy = `http://localhost:5173/post/${post_id}`;
navigator.clipboard.writeText(tocopy);
alert("Copied to clipboard with");
}
async function getUser() {
try {
const response = await fetch('http://localhost:8000/api/users/');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const users = await response.json();
const user = users.find((u) => u.user_id === profile_id.value);
if (user) {
const followerCount = JSON.parse(user.followers).length;
const followingCount = JSON.parse(user.following).length;
userData.value = {
...user,
followerCount,
followingCount,
};
console.log("userData: ", userData.value);
return userData;
} else {
console.error('Benutzer nicht gefunden.');
userData.value = null;
}
} catch (error) {
console.error('Fehler beim Abrufen der Benutzerdaten:', error);
userData.value = null;
}
}
function copyUser(){
const tocopy = `http://localhost:5173/profile/${profile_id.value}`;
navigator.clipboard.writeText(tocopy);
alert("Copied to clipboard");
}
</script>
<template>
<div>
<h2 class="align-middle p-6 text-3xl text-weiss border-b-grau2 border-b ">Profile</h2>
<div class="mb-6" v-if="userData">
<div class="text-weiss p-2 flex justify-center">
<img v-if="userData.user_id != '99' " src="../../assets/default_pp.png" alt="" class="rounded-full size-36">
<img v-else src="../../assets/danielvici_pp.png" alt="" class="rounded-full size-36">
</div>
<div class="text-center p-2 flex flex-col">
<label class="text-xl font-bold m-1 text-weiss" @click="consoleLog()">{{ userData.displayname }}</label>
<label class="text-base m-1 text-grau2">@{{ userData.username }}</label>
</div>
<div class="text-center py-4">
<label class="text-base m-1 text-grau2">Bio:</label>
<p class="text-sm m-1 text-weiss italic">"{{ userData.bio }}"</p>
</div>
<div class="text-grau2 p2 text-center">
<label class="text-base m-1 p-2"> Followers <a class="text-weiss">{{ userData.followerCount }}</a></label>
<label class="text-base m-1 p-2"> Following <a class="text-weiss">{{ userData.followingCount }}</a></label>
</div>
<div class="flex justify-center pt-5">
<button @click="copyUser" class="text-schwarz mx-1 px-1 rounded-lg bg-button-farbe">Share Profile</button>
</div>
</div>
<div v-else class="flex-col justify-center p-5 text-center">
<a class="text-weiss text-3xl"> USER NOT FOUND</a> <br>
<router-link to="/" class="text-button-farbe text-3xl text-center"> Go to Feed</router-link>
</div>
<div>
<h2 class="align-middle p-6 text-xl text-weiss border-y-grau2 border-y ">Posts</h2>
</div>
<div class="sm:overflow-y-auto sm:h-[400px] sm:scrollbar">
<ul v-if="upc.length > 0">
<li v-for="(postitem, indexus) in upc" :key="postitem.user_id" class="border border-grau2 p-3 flex">
<img v-if="postitem.user_id != '99' " src="../../assets/default_pp.png" alt="" class="rounded-full w-16 h-16">
<img v-else src="../../assets/danielvici_pp.png" alt="" class="rounded-full w-16 h-16">
<div>
<div>
<label class="text-lg font-bold m-1 text-weiss">{{ userData.displayname }}</label>
<label class="text-base m-1 text-grau2">@{{ userData.username }}</label>
</div>
<div class="m-2">
<p class="text-sm m-1 text-weiss">{{ postitem.post_text }}</p>
</div>
<div class="sm:flex">
<div class="flex items-center">
<div class="flex">
<img src="../../assets/icons/comment.png" alt="" class="rounded-full align-middle">
<label class="text-sm m-1 text-weiss" v-if="postitem.comments != undefined">{{ postitem.comments }}</label>
<label class="text-sm m-1 text-weiss" v-else>Comments disabled or no comments</label>
</div>
<div class="flex items-center" @click="addLike(postitem.post_id, postitem.user_id, indexus)">
<img alt="" src="../../assets/icons/herz.png" class="align-middle">
<label class="text-sm m-1 text-weiss">{{ postitem.likes }}</label>
</div>
</div>
<br class="sm:hidden">
<div class="flex sm:items-center mx-2">
<button @click="gotoPost(postitem.posts_uuid)" class="text-schwarz mx-1 px-1 rounded-lg bg-button-farbe">View Post</button>
<button @click="copyLink(postitem.posts_uuid)" class="text-schwarz pl-1 mx-1 px-1 rounded-lg bg-button-farbe">Share Post</button>
</div>
</div>
</div>
</li>
</ul>
<p v-else class="text-weiss text-center justify-center text-lg pt-5"> This user has not posted anything yet. </p>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,25 +0,0 @@
<script setup>
import Legal from "./home_components/legal.vue";
import Register_main from "./register_components/register_main.vue";
import router from "../router";
function route_home() {
router.push("/");
}
</script>
<template>
<div id="main" class="bg-hintergrund-farbe sm:flex p-2 sm:justify-between overflow-auto h-screen scrollbar">
<div class="pt-5">
<img src="../assets/esp-logo_no_text.png" alt="" class="rounded-lg h-12 w-24 hover:shadow-2xl hover:shadow-grau-dunkel" @click="route_home">
</div>
<register_main class="sm:inset-0"></register_main>
<div class="sm:inset-y-0 sm:right-0 sw:max-w-36 text-center">
<legal></legal>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,78 +0,0 @@
<script setup lang="ts">
import {ref} from "vue";
import router from "../../router";
let register_input_username = ref("");
let register_input_displayname = ref("");
let register_input_password = ref("");
let register_input_email = ref("");
async function register() {
const username = register_input_username;
const displayname = register_input_displayname;
const email = register_input_email;
const password = register_input_password;
const std_text = "default";
if (username.value === "" || password.value === "" || displayname.value === "" || email.value === "") {
alert("Please fill all fields");
return;
}
console.log("Username: " + username.value + ", Password: " + password.value);
try {
const response = await fetch('http://localhost:8000/api/account/register', {
method: 'POST',
headers: {
'Content-Type': 'login/json',
},
body: JSON.stringify({username: username.value, password: password.value, userGroup: "user", displayname: displayname.value, user_email: email.value, firstname: std_text, surname: std_text}),
});
if (response["status"] == 200) {
const data = await response.json();
localStorage.setItem('isLoggedIn', 'true');
localStorage.setItem('username', username.value);
localStorage.setItem('self_id', data["userId"]);
console.log("SELF REG: " + data["userId"]);
alert("Account created! You will be now redirected");
router.push('/');
router.go(1);
}
const data = await response.json();
console.log(response);
} catch (e) {
console.log("An error has occurred. Please try again later.");
console.error(e);
}
}
</script>
<template>
<div id="main" class="bg-hintergrund-farbe p-2 sm:border-x sm:border-x-grau2 sm:px-20">
<div class="text-3xl pt-20px sm:pt-32"> <!-- ÜBERSCHRIFT-->
<p class="text-weiss text-center">Welcome to <label class="bg-schwarz p-1 rounded-lg mr-1"><span class="text-logo-farbe-lila">E</span><span class="text-logo-farbe-rot">S</span><span class="text-logo-farbe-blau">P</span></label>!</p>
<p class="text-weiss text-center pt-2">Join today!</p>
</div>
<div class="px-20 pt-7"> <!-- FORM --->
<form class="flex flex-col items-center" @submit.prevent="register">
<input class="m-4 sm:w-full max-w-xs bg-grau-dunkel p-4 text-weiss placeholder-grau2 focus:outline-none rounded-lg" v-model="register_input_username" type="text" placeholder="Username" required><br>
<input class="m-4 sm:w-full max-w-xs bg-grau-dunkel p-4 text-weiss placeholder-grau2 focus:outline-none rounded-lg" v-model="register_input_displayname" type="text" placeholder="Displayname" required><br>
<input class="m-4 sm:w-full max-w-xs bg-grau-dunkel p-4 text-weiss placeholder-grau2 focus:outline-none rounded-lg" v-model="register_input_email" type="email" placeholder="E-Mail" required><br>
<input class="m-4 sm:w-full max-w-xs bg-grau-dunkel p-4 text-weiss placeholder-grau2 focus:outline-none rounded-lg" v-model="register_input_password " type="password" placeholder="Password" required><br>
<button class="m-4 bg-button-farbe sm:w-full max-w-xs p-4 text-schwarz rounded-lg">Create Account</button>
</form>
<p class="text-weiss w-100p text-center">Already have an account? <router-link to="/login" class="text-button-farbe">Login</router-link></p>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,30 +0,0 @@
<script setup>
import Navigationbar from "./home_components/navigationbar.vue";
import Legal from "./home_components/legal.vue";
import Search_main from "./search_components/search_main.vue";
import Contacts from "./home_components/contacts.vue";
</script>
<template>
<div class="text-weiss sm:flex">
<div id="left" class="sm:w-72 sm:min-w-72 border-1 border-b-grau">
<navigationbar></navigationbar>
</div>
<div class="sm:w-100p w-screen border-x-2 border-x-grau2">
<div class="border-b-grau2 border-b-2">
<h1 class="text-weiss text-3xl p-4">Search</h1>
</div>
<search_main></search_main>
</div>
<div class="sm:w-1/4">
<contacts></contacts>
<legal></legal>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,221 +0,0 @@
<script setup lang="ts">
import {ref, onMounted} from "vue";
import router from "../../router";
const allItems = ref<any[]>([]);
const feed = ref<any[]>([]);
const feed2 = ref<any[]>([]);
interface search_filter {
u: boolean;
p: boolean;
}
const search_filter_status = ref<search_filter>({
u: true,
p: true,
});
let searched = false;
const usr_search = ref<string | undefined>(undefined);
async function get_posts_user() {
try {
const post_response = await fetch('http://localhost:8000/api/posts');
const postsDATA = await post_response.json();
const user_response = await fetch('http://localhost:8000/api/users');
const usersDATA = await user_response.json();
usersDATA.forEach(user => {
allItems.value.push({...user, id: user.user_id, type: 'user'});
});
postsDATA.forEach(post => {
const author = usersDATA.find(user => user.user_id === post.user_id);
const postWithAuthorInfo = {
...post,
type: 'post',
username: author ? author.username : 'unknown',
displayname: author ? author.displayname : 'unknown',
};
allItems.value.push(postWithAuthorInfo);
});
feed.value = [...allItems.value];
feed2.value = [...allItems.value];
//console.log("Data Loaded:", allItems.value);
} catch (error) {
console.error("Error:", error);
}
}
onMounted(async () => {
get_posts_user();
});
function go_fs(){
searched = true;
feed.value = [];
feed2.value = [];
const combinedFilteredItems = allItems.value
.filter(item => (search_filter_status.value.u == true && item.type === "user") ||
(search_filter_status.value.p == true && item.type === "post"))
.map(item => {
if (item.type === 'post') {
const user = allItems.value.find(u => u.id === item.user_id && u.type === 'user');
return {
...item,
username: user ? user.username : 'unknown',
displayname: user ? user.displayname : 'unknown',
};
}
return item;
});
feed2.value = combinedFilteredItems;
const searchTerm = usr_search.value ? usr_search.value.toLowerCase() : '';
if (!searchTerm) {
feed.value = [...feed2.value];
return;
}
feed.value = feed2.value.filter(item => {
switch (item.type) {
case "user":
return (item.displayname && item.displayname.toLowerCase().includes(searchTerm)) || (item.username && item.username.toLowerCase().includes(searchTerm));
case "post":
return (item.post_text && item.post_text.toLowerCase().includes(searchTerm)) || (item.username && item.username.toLowerCase().includes(searchTerm) || item.displayname && item.displayname.toLowerCase().includes(searchTerm));
default:
return false;
}
});
}
async function addLike(post_id: string | number, user_id: number, index: number) {
try {
feed.value[index].likes++;
const response = await fetch(`http://localhost:8000/api/post/${post_id}/like`, {
method: 'POST',
headers: {'content-type': 'application/json'},
body: `{"userId":${user_id}}`,
});
if (!response.ok) {
const errorText = await response.text();
console.error('Server-Fehlertext:', errorText);
throw new Error(`HTTP error! status: ${response.status}, text: ${errorText}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Fehler beim Liken des Posts:', error);
throw error;
}
}
function gotoPost(post_id: string ) {
localStorage.setItem("viewedpost", post_id);
router.push(`/post/${post_id}`);
console.log("goto post: " + post_id);
}
function copyLink(post_id: string | number) {
const tocopy = `http://localhost:5173/post/${post_id}`;
navigator.clipboard.writeText(tocopy);
alert("Copied to clipboard");
}
function gotoProfile(user_id: string | number) {
router.push(`/profile/${user_id}`);
}
</script>
<template>
<div>
<div class="flex justify-center">
<div class="w-1/2">
<form @submit.prevent="go_fs" class="flex flex-col">
<input type="text" placeholder="Search..." class="w-full m-2 mt-6 p-4 bg-grau-dunkel focus:outline-none rounded-xl placeholder:text-center text-center" v-model="usr_search">
<div class="flex justify-center text-grau2">
<label class="m-2 accent-button-farbe"><input type="checkbox" class="mr-1" v-model="search_filter_status.u">User</label>
<label class="m-2 accent-button-farbe"><input type="checkbox" class="mr-1" v-model="search_filter_status.p">Post</label>
</div>
<button class="text-schwarz pl-1 mx-1 px-1 rounded-lg bg-button-farbe w-1/2 place-self-center">Filter /Search </button>
</form>
</div>
</div>
<div>
<div>
<a class="text-2xl flex justify-center mt-4 pt-2 p-3 border-b-grau2 border-b">Result(s):</a>
</div>
<div v-if="feed.length > 0 && searched == true" class="sm:overflow-y-auto sm:h-[650px] sm:scrollbar">
<div v-for="(bing, i) in feed" :key="bing.id">
<div v-if="bing.type === 'user'" class="pt-2 p-3 border-b-grau2 border-b">
<div class="flex">
<img v-if="bing.user_id != '99' " src="../../assets/default_pp.png" alt="" class="rounded-full w-16 h-16">
<img v-else src="../../assets/danielvici_pp.png" alt="" class="rounded-full w-16 h-16">
<div class="">
<a class="text-lg m-1">{{ bing.displayname }}</a>
<a class="text-base m-1 text-grau2">@{{ bing.username }}</a>
<div>
<a class=" text-sm m-3 text-weiss" v-if="bing.bio">{{ bing.bio }}</a>
<a class=" text-sm m-3 text-grau2 italic" v-else>User has no bio.</a>
</div>
<button @click="gotoProfile(bing.user_id)" class="text-schwarz pl-1 mx-1 px-1 rounded-lg bg-button-farbe"> Go to Profile</button>
</div>
</div>
</div>
<div v-else-if="bing.type === 'post'" class="flex p-3 border-b-grau2 border-b "> <!-- POSTS -->
<img v-if="bing.user_id != '99' " src="../../assets/default_pp.png" alt="" class="rounded-full w-16 h-16">
<img v-else src="../../assets/danielvici_pp.png" alt="" class="rounded-full w-16 h-16">
<div>
<div>
<label class="text-lg m-1 text-weiss">{{ bing.displayname }}</label>
<label class="text-base m-1 text-grau2">@{{ bing.username }}</label>
</div>
<div class="m-2">
<p class="text-sm m-1 text-weiss">{{ bing.post_text }}</p>
</div>
<div class="sm:flex pt-2">
<div class="flex">
<div class="flex">
<img src="../../assets/icons/comment.png" alt="" class="rounded-full align-middle">
<label class="text-sm m-1 text-weiss" v-if="bing.comments != undefined">{{ bing.comments }}</label>
<label class="text-sm m-1 text-weiss" v-else>Comments disabled</label>
</div>
<div class="flex items-center" @click="addLike(bing.posts_uuid, bing.user_id, i)">
<img alt="" src="../../assets/icons/herz.png" class="align-middle">
<label class="text-sm m-1 text-weiss">{{ bing.likes }}</label>
</div>
</div>
<br class="sm:hidden">
<div class="flex sm:tems-center mx-2"> <!-- View Post -->
<button @click="gotoPost(bing.posts_uuid)" class="text-schwarz mx-1 px-1 rounded-lg bg-button-farbe">View Post</button>
<button @click="copyLink(bing.posts_uuid)" class="text-schwarz pl-1 mx-1 px-1 rounded-lg bg-button-farbe">Share Post</button>
<button @click="gotoProfile(bing.user_id)" class="text-schwarz pl-1 mx-1 px-1 rounded-lg bg-button-farbe"> Go to Profile</button>
</div><!-- ENDE -->
</div>
</div>
</div>
</div>
</div>
<div v-else-if="searched == false" class="flex justify-center">
<a class="text-2xl text-logo-farbe-rot p-10 text-center">To see results you have to search</a>
</div>
<div v-else class="flex justify-center">
<a class="text-xl text-logo-farbe-rot p-10 text-center">No Results Found</a>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,35 +0,0 @@
<script setup lang="ts">
import { ref } from 'vue';
import Legal from "./home_components/legal.vue";
import Settings_sidebar from "./settings_components/settings_sidebar.vue";
import Settings_main from "./settings_components/settings_main.vue";
import Navigationbar from "./home_components/navigationbar.vue";
import Contacts from "./home_components/contacts.vue";
const selectedSetting = ref('');
// Aktualisieren der ausgewählten Einstellung
function handleUpdateSetting(setting: string) {
selectedSetting.value = setting;
console.log(`Setting got (S): ${setting}`);
}
</script>
<template>
<div id="main" class="bg-hintergrund-farbe sm:flex">
<div id="left" class="sm:w-72 min-w-72">
<navigationbar></navigationbar>
<settings_sidebar @updateSetting="handleUpdateSetting"></settings_sidebar>
</div>
<div class="w-100p sm:border-x-grau2 sm:border-x-2 my-2">
<settings_main :selectedSetting="selectedSetting"></settings_main>
</div>
<div class="sm:w-1/4">
<contacts></contacts>
<legal></legal>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,82 +0,0 @@
<script setup>
import { ref, onMounted } from "vue";
let self = ref(null); // Initialisiere self mit null
let self_id = ref();
async function getSelf() {
try {
const response = await fetch('http://localhost:8000/api/users', { method: 'GET' });
if (!response.ok) {
console.error(`HTTP-Fehler! Status: ${response.status}`);
self.value = null;
return;
}
const users = await response.json();
const foundUser = users.find(user => {
return String(user.user_id) === self_id.value;
});
if (foundUser) {
self.value = foundUser;
} else {
self.value = null;
}
} catch (error) {
console.error('ERROR:', error);
self.value = null;
}
}
onMounted(() => {
self_id.value = localStorage.getItem('self_id');
getSelf();
console.log("SELF ID (onMounted):", self_id.value);
});
</script>
<template>
<div class="space-y-2 pl-2" v-if="self">
<p class="text-2xl text-weiss pt-2 items-center flex justify-center">{{ self.displayname }}</p>
<div>
<a class="text-lg text-weiss">Username</a><br>
<a class="text-grau2">{{ self.username }}</a>
</div>
<div>
<a class="text-lg text-weiss">User created at</a><br>
<a class="text-grau2">{{ self.account_created }}</a>
</div>
<div>
<a class="text-lg text-weiss">Email</a><br>
<a class="text-grau2">{{ self.user_email }}</a>
</div>
<div>
<a class="text-lg text-weiss">User ID</a><br>
<a class="text-grau2">{{ self.user_id }}</a>
</div>
<div>
<a class="text-lg text-weiss">Firstname</a><br>
<a class="text-grau2">{{ self.firstname }}</a>
</div>
<div>
<a class="text-lg text-weiss">Surname</a><br>
<a class="text-grau2">{{ self.surname }}</a>
</div>
<div>
<a class="text-lg text-weiss">Bio</a><br>
<a class="text-grau2">{{ self.bio }}</a>
</div>
</div>
<div v-else class="flex justify-center items-center">
<p class="text-2xl text-weiss pt-2 items-center flex justify-center">User data is being loaded or does not exist</p>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,37 +0,0 @@
<script setup lang="ts">
import router from "../../router";
function deleteAccount() {
// alert("Account deleted. You will be redirected to the login page.");
router.push("/login");
}
function handleSubmit(event: Event) {
event.preventDefault();
deleteAccount();
}
</script>
<template>
<div class="flex-col flex items-center justify-center">
<div> <!-- HEADER -->
<h1 class="text-weiß text-2xl p-4">Delete Account</h1>
</div>
<div>
<form class="flex flex-col space-y-4 p-4" @submit.prevent="handleSubmit">
<div class="flex flex-col space-y-2 items-center justify-center">
<input type="password" name="password" id="password" placeholder="Password" required class="m-2 w-full max-w-xs bg-grau-dunkel p-4 text-weiss placeholder-grau2 focus:outline-none rounded-lg">
</div>
<div>
<input type="checkbox" name="verification" id="verification" required class="">
<label for="verification" class="p-4">I agree that my account will be deleted permanently.</label>
</div>
<button type="submit" class="bg-logo-farbe-rot text-schwarz text-xl font-bold p-4 mt-8 rounded-lg">Delete Account</button>
</form>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,39 +0,0 @@
<script setup lang="ts">
import router from "../../router";
function reset_password() {
// alert("Account deleted. You will be redirected to the login page.");
router.push("/");
}
function handleSubmit(event: Event) {
event.preventDefault();
reset_password();
}
</script>
<template>
<div>
<div> <!--HEADER-->
<h1 class="text-weiss text-2xl p-3 items-center flex justify-center">Reset Password</h1>
</div>
<div>
<form class="flex flex-col space-y-4 p-4" @submit.prevent="handleSubmit">
<div class="flex flex-col space-y-2">
<input type="password" name="old-password" id="old-password" placeholder="Old Password" class="m-2 w-full max-w-xs bg-grau-dunkel p-4 text-weiss placeholder-grau2 focus:outline-none rounded-lg invalid:border-logo-farbe-rot invalid:border-2">
</div>
<div class="flex flex-col space-y-2">
<input type="password" name="new-password" id="new-password" placeholder="New Passoword" class="m-2 w-full max-w-xs bg-grau-dunkel p-4 text-weiss placeholder-grau2 focus:outline-none rounded-lg invalid:border-logo-farbe-rot invalid:border-2">
</div>
<div class="flex flex-col space-y-2">
<input type="password" name="new-password-repeat" id="new-password-repeat" placeholder=" Repeat new passoword" class="mt-4 m-2 w-full max-w-xs bg-grau-dunkel p-4 text-weiss placeholder-grau2 focus:outline-none rounded-lg invalid:border-logo-farbe-rot invalid:border-2">
</div>
<button type="submit" class="bg-button-farbe text-schwarz text-xl font-bold p-4 mt-8 rounded-lg">Change Password</button>
</form>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,25 +0,0 @@
<script setup lang="ts">
import {defineEmits, ref} from 'vue';
const emit = defineEmits(['updateAccountSetting']);
const selectedSetting = ref('');
function updateAccountSetting(setting: string) {
emit('updateAccountSetting', setting);
selectedSetting.value = setting;
console.log(`Setting selected (SA): ${setting}`);
}
</script>
<template>
<div class=""> <!-- MAIN DIV -->
<div class="flex flex-col text-xl pl-4 pt-5 pr-4 space-y-5 text-grau2"> <!-- BODY -->
<label @click="updateAccountSetting('sa_account-information')" :class="{'text-weiss': selectedSetting === 'sa_account-information' || selectedSetting === ''}">Account Information</label>
<label @click="updateAccountSetting('sa_reset-password')" :class="{'text-weiss': selectedSetting === 'sa_reset-password'}">Reset Password</label>
<label @click="updateAccountSetting('sa_delete-account')" :class="{'text-weiss': selectedSetting === 'sa_delete-account'}">Delete Account</label>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,32 +0,0 @@
<script setup lang="ts">
import {defineProps, ref} from 'vue';
import Sa_accountInformation_comp from "./sa_account-information_comp.vue";
import Sa_reset_password from "./sa_reset_password.vue";
import Sa_delete_account from "./sa_delete_account.vue";
const props2 = defineProps({
selectedAccountSetting: String
});
console.log(`Setting got (SAM): ${props2.selectedAccountSetting}`);
</script>
<template>
<div class="border-l-2 border-l-grau2"> <!-- MAIN DIV -->
<div v-if="props2.selectedAccountSetting === 'sa_account-information'">
<sa_account-information_comp></sa_account-information_comp>
</div>
<div v-else-if="props2.selectedAccountSetting === 'sa_reset-password'">
<sa_reset_password></sa_reset_password>
</div>
<div v-else-if="props2.selectedAccountSetting === 'sa_delete-account'">
<sa_delete_account></sa_delete_account>
</div>
<div v-else>
<sa_account-information_comp></sa_account-information_comp>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,77 +0,0 @@
<script setup lang="ts">
import { ref } from 'vue';
import Settings_account from "./settings_account.vue";
import Settings_account_main from "./settings_account_main.vue";
import Sps_main from "./sps_main.vue";
import So_main from "./so_main.vue";
const props = defineProps({
selectedSetting: String
});
const selectedAccountSetting = ref('');
function handleUpdateAccountSetting(setting: string) {
selectedAccountSetting.value = setting;
}
console.log(`Setting got (SM): ${props.selectedSetting}`);
</script>
<template>
<div class="text-weiss">
<div v-if="props.selectedSetting === 'setting_account'"> <!-- ACCOUNT SETTINGS-->
<div class="border-r-grau2 border-r-1 border-b-grau2 border-b-2"> <!-- HEADER - ACCOUNT SETTINGS-->
<h1 class="text-weiss text-3xl p-4">Account</h1>
</div>
<div class="flex flex-row content-center justify-center autofill:"> <!-- BODY - ACCOUNT SETTINGS-->
<settings_account class="basis-1/2" @updateAccountSetting="handleUpdateAccountSetting"></settings_account>
<settings_account_main class="basis-1/2" :selectedAccountSetting="selectedAccountSetting"></settings_account_main>
</div>
</div>
<div v-else-if="props.selectedSetting === 'setting_privacy'"> <!-- PRIVACY AND SAFTEY-->
<div class="border-r-grau2 border-r-2 border-b-grau2 border-b-2"> <!-- HEADER PRIVACY-->
<h1 class="text-weiss text-3xl p-4">Privacy and Saftey</h1>
</div>
<div> <!-- BODY - ACCOUNT SETTINGS-->
<sps_main></sps_main>
</div>
</div>
<div v-else-if="props.selectedSetting === 'setting_messages'"> <!-- MESSAGES-->
<label class="text-center">Hey! So you found this setting? </label>
</div>
<div v-else-if="props.selectedSetting === 'setting_other'"> <!-- OTHER -->
<div class="border-r-grau2 border-r-1 border-b-grau2 border-b-2"> <!-- HEADER - ACCOUNT SETTINGS-->
<h1 class="text-weiss text-3xl p-4">Other</h1>
</div>
<so_main></so_main>
</div>
<div v-else-if="props.selectedSetting === undefined"> <!-- IF NOTHING SELECTED-->
<label>Select a Setting in the Sidebar</label>
</div>
<div v-else-if="props.selectedSetting === ''"> <!-- IF NOTHING SELECTED-->
<div class="border-r-grau2 border-r-1 border-b-grau2 border-b-2"> <!-- HEADER - ACCOUNT SETTINGS-->
<h1 class="text-weiss text-3xl p-4">Account</h1>
</div>
<div class="flex flex-row content-center justify-center"> <!-- BODY - ACCOUNT SETTINGS-->
<settings_account class="basis-1/2" @updateAccountSetting="handleUpdateAccountSetting"></settings_account>
<settings_account_main class="basis-1/2" :selectedAccountSetting="selectedAccountSetting"></settings_account_main>
</div>
</div>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,26 +0,0 @@
<script setup lang="ts">
import { defineEmits } from 'vue';
import { ref } from 'vue';
const emit = defineEmits(['updateSetting']);
const selectedSetting = ref('');
function updateSetting(setting: string) {
selectedSetting.value = setting;
emit('updateSetting', setting);
console.log(`Setting selected (SS): ${setting}`);
}
</script>
<template>
<div class="text-grau2 font-bold space-y-4 pl-2 pt-5">
<label class="flex text-center rounded-lg" :class="{'text-weiss': selectedSetting === 'setting_account' || selectedSetting === ''}" @click="updateSetting('setting_account')"><img class="pr-2" src="../../assets/icons/user.png" alt="">Account</label>
<label class="flex text-center rounded-lg" :class="{'text-weiss': selectedSetting === 'setting_privacy'}" @click="updateSetting('setting_privacy')"><img class="pr-2" src="../../assets/icons/shield.png" alt="">Privacy and Saftey</label>
<label class="flex text-center rounded-lg" :class="{'text-weiss': selectedSetting === 'setting_message'}" @click="updateSetting('setting_messages')"><img class="pr-2" src="../../assets/icons/mail.png" alt="">Messages</label>
<label class="flex text-center rounded-lg" :class="{'text-weiss': selectedSetting === 'setting_other'}" @click="updateSetting('setting_other')"><img class="pr-2" src="../../assets/icons/other.png" alt="">Other</label>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,23 +0,0 @@
<script setup lang="ts">
import router from "../../router";
function logout() {
console.log("Logout");
localStorage.setItem('isLoggedIn', 'false');
router.push("/login");
}
</script>
<template>
<div class="text-grau2 font-bold space-y-4 pl-2 pt-5 mb-4">
<label class="flex text-center shadow-2xl rounded-lg active:text-weiss" @click="logout"><img class="pr-2" src="../../assets/icons/logout.png" alt="">Logout</label>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,17 +0,0 @@
<script setup>
</script>
<template>
<div class="m-3 flex flex-col">
<label class="text-xl text-grau2 m-2">Blocked Users</label>
<label class="text-xl text-grau2 m-2">Mailing</label>
</div>
</template>
<style scoped>
</style>

View File

@@ -1,7 +1,10 @@
<script setup>
import Navigationbar from "./home_components/navigationbar.vue";
import Feed from "./home_components/feed.vue";
import Contacts from "./home_components/contacts.vue";
import Legal from "./home_components/legal.vue";
import Trending from "./home_components/trending.vue";
import QuickSearch from "./home_components/quick_search.vue";
</script>
<template>
@@ -13,6 +16,7 @@ import Legal from "./home_components/legal.vue";
<label class="text-weiss text-5xl align-middle mx-60 pt-60">This site is currently Work in Progress...</label>
</div>
<div id="right">
<quick-search> </quick-search>
<contacts></contacts>
<legal></legal>
</div>

View File

@@ -1,5 +1,6 @@
/// <reference lib="deno.ns" />
import './assets/main.css';
import {createApp, onMounted} from 'vue';
import { createApp } from 'vue';
// @ts-ignore:
import App from '../src/App.vue';
// @ts-ignore:
@@ -7,4 +8,4 @@ import router from "./router/index.ts";
const app = createApp(App);
app.use(router);
app.mount('#app');
app.mount('#app');

View File

@@ -1,90 +1,37 @@
// File: `src/router/index.ts`
/// <reference types="vite/client" />
import { createRouter, createWebHistory } from "vue-router";
import Home from "../../src/components/Home.vue";
// Vue components imported here.
// the vue components are the Pages that will be rendered
// at these URL's.
import Home from "../components/Home.vue";
import Login from "../components/Login.vue";
import wip from "../components/wip.vue";
import settings from "../components/settings.vue";
import notifications from "../components/notifications.vue";
import register from "../components/register.vue";
import search from "../components/search.vue";
import post from "../components/posts.vue";
import profile from "../components/profile.vue";
import messages from "../components/messages.vue";
// The routing does not happen automatically
// Each route has to be defined here, or it wont work.
const routes = [
{
path: "/",
name: "home",
component: Home,
meta: { requiresAuth: true }
},
{
path: "/login",
name: "login",
component: Login
component: Login,
},
{
path: "/wip",
name: "Work in Progress",
component: wip,
meta: { requiresAuth: true }
},
{
path: "/settings",
name: "Settings",
component: settings,
meta: { requiresAuth: true }
},
{
path: "/notifications",
name: "Notifications",
component: notifications,
meta: { requiresAuth: true }
},
{
path: "/register",
name: "Register",
component: register
},
{
path: "/search",
name: "Search",
component: search,
meta: { requiresAuth: true }
},
{
path: "/post/:id",
name: "PostDetail",
component: post,
meta: { requiresAuth: true }
},
{
path: "/profile/:username",
name: "Profile",
component: profile,
props: true,
meta: { requiresAuth: true }
},
{
path: "/messages",
name: "Messages",
component: messages,
meta: { requiresAuth: true }
}
];
]
const router = createRouter({
history: createWebHistory("/"),
routes,
});
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && localStorage.getItem("isLoggedIn") !== "true") {
alert("not logged in ");
next({ name: "login" });
} else {
next();
}
});
export default router;
export default router;

View File

@@ -21,8 +21,7 @@ export default {
'35p': '30.825%',
}
},
plugins: ['tailwind-scrollbar', 'tailwind-scrollbar-hide'],
colors: {
colors: {
'logo-farbe-lila': '#5500a2',
'logo-farbe-rot': '#a2002b',
'logo-farbe-blau': '#0b1074',