Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4fb87cc127 | ||
|
|
def0f2bd9c | ||
|
|
68aa7c20f3 | ||
|
|
6e87e5003e | ||
|
|
0ecd265ade | ||
|
|
895a40fe67 | ||
|
|
cfcfd4ba5e | ||
|
|
9e7039c72c | ||
|
|
029fc10de7 | ||
|
|
8b594990ee | ||
|
|
65ced2f3d3 | ||
|
|
497d5aa28f | ||
|
|
8b992017ba | ||
|
|
aeaae9fc58 | ||
|
|
4c80caa52a | ||
|
|
3c6fdd0b59 | ||
|
|
4dfa695458 | ||
|
|
010e518828 | ||
|
|
b0f8a51cc8 | ||
|
|
7a6152be51 | ||
|
|
f45945474d | ||
|
|
064b864246 | ||
|
|
4d06db689d | ||
|
|
c786ddd895 | ||
|
|
108b3f0d50 | ||
|
|
abe39c0797 | ||
|
|
3d31061087 |
6
.github/workflows/deploy.yml
vendored
@@ -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
@@ -13,6 +13,8 @@ dist-ssr
|
||||
.vite
|
||||
*.local
|
||||
*.sqlite
|
||||
*.idea
|
||||
.env
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
|
||||
33
README.md
@@ -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>
|
||||
@@ -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.
|
||||
|
||||
@@ -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', '[]', '[]', '[]', '[]'),
|
||||
|
||||
@@ -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
@@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
<template >
|
||||
<template>
|
||||
<router-view />
|
||||
</template>
|
||||
|
Before Width: | Height: | Size: 408 B |
|
Before Width: | Height: | Size: 574 B |
|
Before Width: | Height: | Size: 587 B |
|
Before Width: | Height: | Size: 501 B |
|
Before Width: | Height: | Size: 271 B |
|
Before Width: | Height: | Size: 340 B |
|
Before Width: | Height: | Size: 538 B |
@@ -1,5 +1,3 @@
|
||||
@plugin 'tailwind-scrollbar';
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
38
src/components/home_components/HelloWorld.vue
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
16
src/components/home_components/quick_search.vue
Normal 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>
|
||||
@@ -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"},
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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');
|
||||
@@ -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;
|
||||
|
||||
@@ -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',
|
||||
|
||||