Showcase ref bug
This commit is contained in:
parent
757d790e54
commit
c1a5dd9afe
21 changed files with 339 additions and 1330 deletions
23
README.md
23
README.md
|
@ -49,23 +49,30 @@ To get started with li'l Judd, follow the instructions below.
|
||||||
VITE_DISCORD_CLIENT=your_discord_client_id
|
VITE_DISCORD_CLIENT=your_discord_client_id
|
||||||
VITE_DISCORD_CLIENT_SECRET=your_discord_client_secret
|
VITE_DISCORD_CLIENT_SECRET=your_discord_client_secret
|
||||||
VITE_DISCORD_BOT_TOKEN=your_discord_bot_token
|
VITE_DISCORD_BOT_TOKEN=your_discord_bot_token
|
||||||
|
VITE_DISCORD_BOT_PERMISSIONS=18977581952080
|
||||||
|
|
||||||
VITE_AUTH_SECRET=your_auth_secret
|
VITE_AUTH_SECRET=your_auth_secret
|
||||||
|
|
||||||
VITE_DATABASE_URL=your_database_url
|
VITE_DATABASE_URL=your_database_url
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Development
|
Recieve your discord applications client id & secret, as well as the bot token from the [Applications dashboard](https://discord.com/developers/applications/).
|
||||||
|
|
||||||
Specify `VITE_AUTH_REDIRECT_PROXY_URL` only if necessary, particularly when setting up a reverse proxy to test authentication with callbacks to your development box. [Auth.js Docs Reference](https://authjs.dev/reference/nextjs/#redirectproxyurl)
|
How to generate your `VITE_AUTH_SECRET` with [`openssl rand -base64 32`](https://authjs.dev/reference/core#secret).
|
||||||
|
|
||||||
The duplicate `DATABASE_URL` is only needed for Drizzle Studio.
|
Composite your `VITE_DATABASE_URL` like [`postgres://postgres:adminadmin@0.0.0.0:5432/db`](https://orm.drizzle.team/docs/get-started-postgresql#postgresjs).
|
||||||
|
|
||||||
```
|
#### Development
|
||||||
VITE_AUTH_REDIRECT_PROXY_URL=your_auth_redirect_proxy_url
|
|
||||||
|
|
||||||
DATABASE_URL=your_database_url
|
Specify `VITE_AUTH_REDIRECT_PROXY_URL` only if necessary, particularly when setting up a reverse proxy to test authentication with callbacks to your development box. [Auth.js Docs Reference](https://authjs.dev/reference/nextjs/#redirectproxyurl)
|
||||||
```
|
|
||||||
|
The duplicate `DATABASE_URL` is only needed for Drizzle Studio.
|
||||||
|
|
||||||
|
```
|
||||||
|
VITE_AUTH_REDIRECT_PROXY_URL=your_auth_redirect_proxy_url
|
||||||
|
|
||||||
|
DATABASE_URL=your_database_url
|
||||||
|
```
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
|
@ -120,6 +127,6 @@ If you'd like to contribute to li'l Judd, feel free to open an issue or submit a
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the [MIT License](LICENSE).
|
This project is licensed under the [GPL v3 License](LICENSE).
|
||||||
|
|
||||||
Happy splatting! 🦑🎮
|
Happy splatting! 🦑🎮
|
||||||
|
|
|
@ -16,13 +16,6 @@
|
||||||
"@auth/core": "^0.19.0",
|
"@auth/core": "^0.19.0",
|
||||||
"@auth/drizzle-adapter": "^0.3.12",
|
"@auth/drizzle-adapter": "^0.3.12",
|
||||||
"@auth/solid-start": "0.1.2",
|
"@auth/solid-start": "0.1.2",
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.5.1",
|
|
||||||
"@fortawesome/pro-duotone-svg-icons": "^6.5.1",
|
|
||||||
"@fortawesome/pro-light-svg-icons": "^6.5.1",
|
|
||||||
"@fortawesome/pro-regular-svg-icons": "^6.5.1",
|
|
||||||
"@fortawesome/pro-solid-svg-icons": "^6.5.1",
|
|
||||||
"@fortawesome/pro-thin-svg-icons": "^6.5.1",
|
|
||||||
"@fortawesome/sharp-solid-svg-icons": "^6.5.1",
|
|
||||||
"@solidjs/meta": "^0.29.2",
|
"@solidjs/meta": "^0.29.2",
|
||||||
"@solidjs/router": "^0.10.9",
|
"@solidjs/router": "^0.10.9",
|
||||||
"@solidjs/start": "^0.4.9",
|
"@solidjs/start": "^0.4.9",
|
||||||
|
|
|
@ -14,27 +14,6 @@ dependencies:
|
||||||
'@auth/solid-start':
|
'@auth/solid-start':
|
||||||
specifier: 0.1.2
|
specifier: 0.1.2
|
||||||
version: 0.1.2(@auth/core@0.19.1)(solid-js@1.8.11)(solid-start@0.2.32)
|
version: 0.1.2(@auth/core@0.19.1)(solid-js@1.8.11)(solid-start@0.2.32)
|
||||||
'@fortawesome/fontawesome-svg-core':
|
|
||||||
specifier: ^6.5.1
|
|
||||||
version: 6.5.1
|
|
||||||
'@fortawesome/pro-duotone-svg-icons':
|
|
||||||
specifier: ^6.5.1
|
|
||||||
version: 6.5.1
|
|
||||||
'@fortawesome/pro-light-svg-icons':
|
|
||||||
specifier: ^6.5.1
|
|
||||||
version: 6.5.1
|
|
||||||
'@fortawesome/pro-regular-svg-icons':
|
|
||||||
specifier: ^6.5.1
|
|
||||||
version: 6.5.1
|
|
||||||
'@fortawesome/pro-solid-svg-icons':
|
|
||||||
specifier: ^6.5.1
|
|
||||||
version: 6.5.1
|
|
||||||
'@fortawesome/pro-thin-svg-icons':
|
|
||||||
specifier: ^6.5.1
|
|
||||||
version: 6.5.1
|
|
||||||
'@fortawesome/sharp-solid-svg-icons':
|
|
||||||
specifier: ^6.5.1
|
|
||||||
version: 6.5.1
|
|
||||||
'@solidjs/meta':
|
'@solidjs/meta':
|
||||||
specifier: ^0.29.2
|
specifier: ^0.29.2
|
||||||
version: 0.29.3(solid-js@1.8.11)
|
version: 0.29.3(solid-js@1.8.11)
|
||||||
|
@ -2048,68 +2027,6 @@ packages:
|
||||||
resolution: {integrity: sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==}
|
resolution: {integrity: sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
/@fortawesome/fontawesome-common-types@6.5.1:
|
|
||||||
resolution: {integrity: sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==, tarball: https://npm.fontawesome.com/@fortawesome/fontawesome-common-types/-/6.5.1/fontawesome-common-types-6.5.1.tgz}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
requiresBuild: true
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@fortawesome/fontawesome-svg-core@6.5.1:
|
|
||||||
resolution: {integrity: sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==, tarball: https://npm.fontawesome.com/@fortawesome/fontawesome-svg-core/-/6.5.1/fontawesome-svg-core-6.5.1.tgz}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
requiresBuild: true
|
|
||||||
dependencies:
|
|
||||||
'@fortawesome/fontawesome-common-types': 6.5.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@fortawesome/pro-duotone-svg-icons@6.5.1:
|
|
||||||
resolution: {integrity: sha512-ywRh7WpcUD4To4TBFZc2EzbFblWiccNf9wwLFK56J7t8mO9ITQJAIPpT8x7DBrqejfbw9B4F6aH5fY6mfi0egg==, tarball: https://npm.fontawesome.com/@fortawesome/pro-duotone-svg-icons/-/6.5.1/pro-duotone-svg-icons-6.5.1.tgz}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
requiresBuild: true
|
|
||||||
dependencies:
|
|
||||||
'@fortawesome/fontawesome-common-types': 6.5.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@fortawesome/pro-light-svg-icons@6.5.1:
|
|
||||||
resolution: {integrity: sha512-qcBN5RESCPhbWRvHL5N5ovxvYzj2KbpKoSWPJ1TRce1jSsQgBx6hN4SCzzzYJkoiIO43L1/n+NjEQHb0YYtg6g==, tarball: https://npm.fontawesome.com/@fortawesome/pro-light-svg-icons/-/6.5.1/pro-light-svg-icons-6.5.1.tgz}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
requiresBuild: true
|
|
||||||
dependencies:
|
|
||||||
'@fortawesome/fontawesome-common-types': 6.5.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@fortawesome/pro-regular-svg-icons@6.5.1:
|
|
||||||
resolution: {integrity: sha512-Rd7Q7Vff68l/YtFKB4EJW/YJ5eXYk7TqejyDTapOI1sn3/AFMEc8CVCOsPfi4+6qGrJy16hlNvgpigIy5gkW7A==, tarball: https://npm.fontawesome.com/@fortawesome/pro-regular-svg-icons/-/6.5.1/pro-regular-svg-icons-6.5.1.tgz}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
requiresBuild: true
|
|
||||||
dependencies:
|
|
||||||
'@fortawesome/fontawesome-common-types': 6.5.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@fortawesome/pro-solid-svg-icons@6.5.1:
|
|
||||||
resolution: {integrity: sha512-UnJzqw7w+RVtEnQ2Bqg09bGYkJEZRkTnbgweZDTznHjtxsJzQdJkD3hJPL6N00c8GbWpRYslNDnTNDGVSd94cQ==, tarball: https://npm.fontawesome.com/@fortawesome/pro-solid-svg-icons/-/6.5.1/pro-solid-svg-icons-6.5.1.tgz}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
requiresBuild: true
|
|
||||||
dependencies:
|
|
||||||
'@fortawesome/fontawesome-common-types': 6.5.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@fortawesome/pro-thin-svg-icons@6.5.1:
|
|
||||||
resolution: {integrity: sha512-tVb+5q+QQiSG3enV9+PpeFKe7wd+TK5zZ9q9iqr4Zj2UbxdV2o6SGcA5h0oeWVH2eHVqiIHxfEf7XbB8/ZioAQ==, tarball: https://npm.fontawesome.com/@fortawesome/pro-thin-svg-icons/-/6.5.1/pro-thin-svg-icons-6.5.1.tgz}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
requiresBuild: true
|
|
||||||
dependencies:
|
|
||||||
'@fortawesome/fontawesome-common-types': 6.5.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@fortawesome/sharp-solid-svg-icons@6.5.1:
|
|
||||||
resolution: {integrity: sha512-IYRaD4FKokprj63Qu+blYXgLioPFQx3ecimYk8ENd4cpySOYgP8tPRy5TSSq0udkXKAjfkeYUAXhQ88OD0qyiw==, tarball: https://npm.fontawesome.com/@fortawesome/sharp-solid-svg-icons/-/6.5.1/sharp-solid-svg-icons-6.5.1.tgz}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
requiresBuild: true
|
|
||||||
dependencies:
|
|
||||||
'@fortawesome/fontawesome-common-types': 6.5.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@hapi/hoek@9.3.0:
|
/@hapi/hoek@9.3.0:
|
||||||
resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
|
resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// @refresh reload
|
// @refresh reload
|
||||||
import "@fortawesome/fontawesome-svg-core/styles.css";
|
// import "@fortawesome/fontawesome-svg-core/styles.css";
|
||||||
import { Meta, MetaProvider, Title } from "@solidjs/meta";
|
import { Meta, MetaProvider, Title } from "@solidjs/meta";
|
||||||
import { Router } from "@solidjs/router";
|
import { Router } from "@solidjs/router";
|
||||||
import { FileRoutes } from "@solidjs/start";
|
import { FileRoutes } from "@solidjs/start";
|
||||||
|
|
|
@ -1,151 +0,0 @@
|
||||||
import {
|
|
||||||
FaSymbol,
|
|
||||||
FlipProp,
|
|
||||||
IconDefinition,
|
|
||||||
IconProp,
|
|
||||||
PullProp,
|
|
||||||
RotateProp,
|
|
||||||
SizeProp,
|
|
||||||
Transform,
|
|
||||||
} from "@fortawesome/fontawesome-svg-core";
|
|
||||||
import { type JSX } from "solid-js";
|
|
||||||
|
|
||||||
export interface FontAwesomeIconProps
|
|
||||||
extends Omit<
|
|
||||||
JSX.SvgSVGAttributes<SVGSVGElement>,
|
|
||||||
"children" | "mask" | "transform"
|
|
||||||
> {
|
|
||||||
icon: IconDefinition;
|
|
||||||
mask?: IconProp;
|
|
||||||
maskId?: string;
|
|
||||||
color?: string;
|
|
||||||
spin?: boolean;
|
|
||||||
spinPulse?: boolean;
|
|
||||||
spinReverse?: boolean;
|
|
||||||
pulse?: boolean;
|
|
||||||
beat?: boolean;
|
|
||||||
fade?: boolean;
|
|
||||||
beatFade?: boolean;
|
|
||||||
bounce?: boolean;
|
|
||||||
shake?: boolean;
|
|
||||||
flash?: boolean;
|
|
||||||
border?: boolean;
|
|
||||||
fixedWidth?: boolean;
|
|
||||||
inverse?: boolean;
|
|
||||||
listItem?: boolean;
|
|
||||||
flip?: FlipProp;
|
|
||||||
size?: SizeProp;
|
|
||||||
pull?: PullProp;
|
|
||||||
rotation?: RotateProp;
|
|
||||||
transform?: string | Transform;
|
|
||||||
symbol?: FaSymbol;
|
|
||||||
style?: JSX.CSSProperties;
|
|
||||||
tabIndex?: number;
|
|
||||||
title?: string;
|
|
||||||
titleId?: string;
|
|
||||||
swapOpacity?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const idPool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
||||||
function nextUniqueId() {
|
|
||||||
let size = 12;
|
|
||||||
let id = "";
|
|
||||||
|
|
||||||
while (size-- > 0) {
|
|
||||||
id += idPool[(Math.random() * 62) | 0];
|
|
||||||
}
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
function Path(props: { d: string | string[] }) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{typeof props.d === "string" ? (
|
|
||||||
<path fill="currentColor" d={props.d} />
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<path class="fa-secondary" fill="currentColor" d={props.d[0]} />
|
|
||||||
<path class="fa-primary" fill="currentColor" d={props.d[1]} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function FontAwesomeIcon(props: FontAwesomeIconProps) {
|
|
||||||
const titleId = () =>
|
|
||||||
props.title
|
|
||||||
? "svg-inline--fa-title-".concat(props.titleId || nextUniqueId())
|
|
||||||
: undefined;
|
|
||||||
// Get CSS class list from the props object
|
|
||||||
function attributes() {
|
|
||||||
const defaultClasses = {
|
|
||||||
"svg-inline--fa": true,
|
|
||||||
[`fa-${props.icon.iconName}`]: true,
|
|
||||||
[props.class ?? ""]:
|
|
||||||
typeof props.class !== "undefined" && props.class !== null,
|
|
||||||
...props.classList,
|
|
||||||
};
|
|
||||||
|
|
||||||
// map of CSS class names to properties
|
|
||||||
const faClasses = {
|
|
||||||
"fa-beat": props.beat,
|
|
||||||
"fa-fade": props.fade,
|
|
||||||
"fa-beat-fade": props.beatFade,
|
|
||||||
"fa-bounce": props.bounce,
|
|
||||||
"fa-shake": props.shake,
|
|
||||||
"fa-flash": props.flash,
|
|
||||||
"fa-spin": props.spin,
|
|
||||||
"fa-spin-reverse": props.spinReverse,
|
|
||||||
"fa-spin-pulse": props.spinPulse,
|
|
||||||
"fa-pulse": props.pulse,
|
|
||||||
"fa-fw": props.fixedWidth,
|
|
||||||
"fa-inverse": props.inverse,
|
|
||||||
"fa-border": props.border,
|
|
||||||
"fa-li": props.listItem,
|
|
||||||
"fa-flip": typeof props.flip !== "undefined" && props.flip !== null,
|
|
||||||
"fa-flip-horizontal":
|
|
||||||
props.flip === "horizontal" || props.flip === "both",
|
|
||||||
"fa-flip-vertical": props.flip === "vertical" || props.flip === "both",
|
|
||||||
[`fa-${props.size}`]:
|
|
||||||
typeof props.size !== "undefined" && props.size !== null,
|
|
||||||
[`fa-rotate-${props.rotation}`]:
|
|
||||||
typeof props.rotation !== "undefined" && props.size !== null,
|
|
||||||
[`fa-pull-${props.pull}`]:
|
|
||||||
typeof props.pull !== "undefined" && props.pull !== null,
|
|
||||||
"fa-swap-opacity": props.swapOpacity,
|
|
||||||
};
|
|
||||||
|
|
||||||
const attributes = {
|
|
||||||
focusable: !!props.title,
|
|
||||||
"aria-hidden": !props.title,
|
|
||||||
role: "img",
|
|
||||||
xmlns: "http://www.w3.org/2000/svg",
|
|
||||||
"aria-labelledby": titleId(),
|
|
||||||
"data-prefix": props.icon.prefix,
|
|
||||||
"data-icon": props.icon.iconName,
|
|
||||||
"data-fa-transform": props.transform,
|
|
||||||
"data-fa-mask": props.mask,
|
|
||||||
"data-fa-mask-id": props.maskId,
|
|
||||||
"data-fa-symbol": props.symbol,
|
|
||||||
tabIndex: props.tabIndex,
|
|
||||||
classList: { ...defaultClasses, ...faClasses },
|
|
||||||
color: props.color,
|
|
||||||
style: props.style,
|
|
||||||
viewBox: `0 0 ${props.icon.icon[0]} ${props.icon.icon[1]}`,
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
// return the complete class list
|
|
||||||
return attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<svg {...attributes()}>
|
|
||||||
{/* <Show when={props.title}>
|
|
||||||
<title id={titleId()}>{props.title}</title>
|
|
||||||
</Show> */}
|
|
||||||
<Path d={props.icon.icon[4]} />
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,7 +1,5 @@
|
||||||
import { faCirclePlus } from "@fortawesome/pro-regular-svg-icons";
|
|
||||||
import { JSX, Show, Suspense } from "solid-js";
|
import { JSX, Show, Suspense } from "solid-js";
|
||||||
import "../styles/components/NavBar.scss";
|
import "../styles/components/NavBar.scss";
|
||||||
import { FontAwesomeIcon } from "./FontAwesomeIcon";
|
|
||||||
import NavUser from "./NavUser";
|
import NavUser from "./NavUser";
|
||||||
|
|
||||||
export function Li(props: {
|
export function Li(props: {
|
||||||
|
@ -40,10 +38,10 @@ function NavBar() {
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="flex-row responsive thick">
|
<ul class="flex-row responsive thick">
|
||||||
<Li
|
<Li
|
||||||
href="https://discord.com/api/oauth2/authorize?client_id=1024410658973941862&permissions=18977581952080&scope=bot"
|
href={`https://discord.com/api/oauth2/authorize?client_id=${import.meta.env.VITE_DISCORD_CLIENT_ID}&permissions=${import.meta.env.VITE_DISCORD_BOT_PERMISSIONS}&scope=bot`}
|
||||||
name="Invite to your server"
|
name="Invite to your server"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon class="lower" icon={faCirclePlus} size="xl" />
|
{/* <FontAwesomeIcon class="lower" icon={faCirclePlus} size="xl" /> */}
|
||||||
</Li>
|
</Li>
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<NavUser />
|
<NavUser />
|
||||||
|
|
|
@ -1,84 +1,74 @@
|
||||||
import { getSession } from "@auth/solid-start";
|
|
||||||
import { signIn, signOut } from "@auth/solid-start/client";
|
import { signIn, signOut } from "@auth/solid-start/client";
|
||||||
import {
|
import { Show } from "solid-js";
|
||||||
faArrowRightFromBracket,
|
|
||||||
faArrowRightToBracket,
|
|
||||||
faGear,
|
|
||||||
} from "@fortawesome/pro-regular-svg-icons";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import { Show, createResource } from "solid-js";
|
|
||||||
import { getRequestEvent } from "solid-js/web";
|
|
||||||
import db from "~/drizzle";
|
|
||||||
import { users } from "~/drizzle/schema";
|
|
||||||
import { authOptions } from "~/server/auth";
|
|
||||||
import { FontAwesomeIcon } from "./FontAwesomeIcon";
|
|
||||||
import { Li } from "./NavBar";
|
import { Li } from "./NavBar";
|
||||||
|
|
||||||
const initialUser = {
|
// const initialUser = {
|
||||||
id: "",
|
// id: "",
|
||||||
name: null as string | null,
|
// name: null as string | null,
|
||||||
email: "",
|
// email: "",
|
||||||
emailVerified: null as Date | null,
|
// emailVerified: null as Date | null,
|
||||||
image: null as string | null,
|
// image: null as string | null,
|
||||||
};
|
// };
|
||||||
|
|
||||||
async function getUser() {
|
// async function getUser() {
|
||||||
"use server";
|
// "use server";
|
||||||
|
|
||||||
const event = getRequestEvent();
|
// const event = getRequestEvent();
|
||||||
if (!event)
|
// if (!event)
|
||||||
return { success: false, message: "No request event!", ...initialUser };
|
// return { success: false, message: "No request event!", ...initialUser };
|
||||||
|
|
||||||
const session = await getSession(event.request, authOptions);
|
// const session = await getSession(event.request, authOptions);
|
||||||
if (!session?.user?.id)
|
// if (!session?.user?.id)
|
||||||
return { success: false, message: "No user with id!", ...initialUser };
|
// return { success: false, message: "No user with id!", ...initialUser };
|
||||||
|
|
||||||
const user = (
|
// const user = (
|
||||||
await db
|
// await db
|
||||||
.selectDistinct()
|
// .selectDistinct()
|
||||||
.from(users)
|
// .from(users)
|
||||||
.where(eq(users.id, session.user?.id))
|
// .where(eq(users.id, session.user?.id))
|
||||||
.limit(1)
|
// .limit(1)
|
||||||
.execute()
|
// .execute()
|
||||||
)[0];
|
// )[0];
|
||||||
|
|
||||||
return { success: true, message: "", ...user };
|
// return { success: true, message: "", ...user };
|
||||||
}
|
// }
|
||||||
|
|
||||||
function NavUser() {
|
function NavUser() {
|
||||||
const [user] = createResource(() =>
|
// const location = useLocation();
|
||||||
getUser().then((e) => {
|
|
||||||
if (!e.success) console.log(1, e.message);
|
// const [user] = createResource(() =>
|
||||||
console.log(2, e);
|
// getUser().then((e) => {
|
||||||
return e;
|
// if (!e.success) console.log(1, location.pathname, e.message);
|
||||||
}),
|
// console.log(2, location.pathname, e);
|
||||||
);
|
// return e;
|
||||||
|
// }),
|
||||||
|
// );
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Show
|
<Show
|
||||||
when={user()?.id}
|
when={false}
|
||||||
fallback={
|
fallback={
|
||||||
<Li
|
<Li
|
||||||
href="#"
|
href="#"
|
||||||
name="Login"
|
name="Login"
|
||||||
action={() => signIn("discord", { callbackUrl: "/config" })}
|
action={() => signIn("discord", { callbackUrl: "/config" })}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
{/* <FontAwesomeIcon
|
||||||
class="secondary"
|
class="secondary"
|
||||||
icon={faArrowRightToBracket}
|
icon={faArrowRightToBracket}
|
||||||
size="xl"
|
size="xl"
|
||||||
/>
|
/> */}
|
||||||
</Li>
|
</Li>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Li href="/config">
|
<Li href="/config">
|
||||||
<div class="swap lower">
|
<div class="swap lower">
|
||||||
<img class="primary" src={user()?.image ?? ""} alt="User pfp" />
|
{/* <img class="primary" src={user()?.image ?? ""} alt="User pfp" /> */}
|
||||||
<FontAwesomeIcon class="secondary" icon={faGear} size="xl" />
|
{/* <FontAwesomeIcon class="secondary" icon={faGear} size="xl" /> */}
|
||||||
</div>
|
</div>
|
||||||
</Li>
|
</Li>
|
||||||
<Li href="#" action={() => signOut({ callbackUrl: "/" })}>
|
<Li href="#" action={() => signOut({ callbackUrl: "/" })}>
|
||||||
<FontAwesomeIcon icon={faArrowRightFromBracket} size="xl" />
|
{/* <FontAwesomeIcon icon={faArrowRightFromBracket} size="xl" /> */}
|
||||||
</Li>
|
</Li>
|
||||||
</Show>
|
</Show>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
import { Title } from "@solidjs/meta";
|
|
||||||
import { HttpStatusCode } from "@solidjs/start";
|
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/index.scss";
|
|
||||||
|
|
||||||
export default function NotFound() {
|
|
||||||
return (
|
|
||||||
<Layout site="index">
|
|
||||||
<Title>Not Found</Title>
|
|
||||||
<HttpStatusCode code={404} />
|
|
||||||
<section class="index">
|
|
||||||
<h1>404 - Whoops, ink spill!</h1>
|
|
||||||
<h5>li'l Judd couldn't find this turf.</h5>
|
|
||||||
<div>
|
|
||||||
<p class="p1">
|
|
||||||
Head back to <a href="/">base</a> and splat into action from there!
|
|
||||||
🦑🕹️
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/about.scss";
|
|
||||||
|
|
||||||
function about() {
|
|
||||||
return (
|
|
||||||
<Layout site="about">
|
|
||||||
<h1>About</h1>
|
|
||||||
<section>
|
|
||||||
<h2>Why does this bot exist?</h2>
|
|
||||||
<p>
|
|
||||||
We had a person in our team, who sent{" "}
|
|
||||||
<a href="/assets/screenshots/oldplanningmsg.png" target="_blank">
|
|
||||||
these planning messages
|
|
||||||
</a>{" "}
|
|
||||||
and I thought that this should be automated. Some time later the first
|
|
||||||
version of li'l Judd was born. Today the bot has more features and
|
|
||||||
keeps getting more of them! It is designed to actually improve the
|
|
||||||
Splatoon experience and not be the 10000th moderation and general
|
|
||||||
utility bot with the same features as all bots.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>Who is behind this?</h2>
|
|
||||||
<p>
|
|
||||||
The bot is currently being developed by{" "}
|
|
||||||
<a href="/contact">moonleay</a> (hey that's me!) with occasional
|
|
||||||
help from his friends!
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>How can I trust you?</h2>
|
|
||||||
<p>
|
|
||||||
The bot only requests permissions, which are needed for it to work.
|
|
||||||
Additionally, if you want to check how the bot works under the hood,
|
|
||||||
you can
|
|
||||||
<a href="https://git.moonleay.net/DiscordBots/lilJudd">
|
|
||||||
read the code
|
|
||||||
</a>
|
|
||||||
and if you still don't trust me, you can always host the bot yourself!
|
|
||||||
A guide on how to do that can be found in the README of the git
|
|
||||||
project.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>Where is my data stored?</h2>
|
|
||||||
<p>
|
|
||||||
Your data is stored on a VPS from Contabo in Germany. The bot used to
|
|
||||||
be hosted on a server in my basement, but I moved it to a VPS, because
|
|
||||||
my internet connection was not stable enough.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>So whats in the future?</h2>
|
|
||||||
<p>
|
|
||||||
I plan on adding features, which are aimed to improve your and your
|
|
||||||
teams competitive experience! You can check out my public todo list{" "}
|
|
||||||
<a
|
|
||||||
href="https://todo.moonleay.net/share/OmisuzgPDdsrCAXKjGrTfYzWwqNDNclOMGJWeMsi/auth?view=kanban"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
here
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>Hey, there is this really cool idea I have! Can you add it?</h2>
|
|
||||||
<p>
|
|
||||||
Just message me! I can't promise anything, but I am always open to new
|
|
||||||
ideas and improvements! You can find ways to contact me{" "}
|
|
||||||
<a href="/contact">here</a>.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default about;
|
|
|
@ -1,196 +0,0 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/acknowledgements.scss";
|
|
||||||
|
|
||||||
function acknowledgements() {
|
|
||||||
return (
|
|
||||||
<Layout site="acknowledgements">
|
|
||||||
<h1>Acknowledgements</h1>
|
|
||||||
<section>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
<p>tool</p>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
<p>license</p>
|
|
||||||
</th>
|
|
||||||
<th>
|
|
||||||
<p>page</p>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>Kotlin</p>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a
|
|
||||||
href="https://kotlinlang.org/docs/faq.html#is-kotlin-free"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
Apache license 2.0
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a href="https://kotlinlang.org/" target="_blank">
|
|
||||||
website
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>Kord</p>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a
|
|
||||||
href="https://github.com/kordlib/kord/blob/main/LICENSE"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
MIT license
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a href="https://kord.dev/" target="_blank">
|
|
||||||
website
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>Kord Extensions</p>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a
|
|
||||||
href="https://github.com/Kord-Extensions/kord-extensions/blob/root/LICENSE"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
Mozilla Public License 2.0
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a href="https://kordex.kotlindiscord.com/" target="_blank">
|
|
||||||
website
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>PostgreSQL</p>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a
|
|
||||||
href="https://www.postgresql.org/about/licence/"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
PostgreSQL license
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a href="https://www.postgresql.org/" target="_blank">
|
|
||||||
website
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>kotlinx-coroutines-core</p>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a
|
|
||||||
href="https://github.com/Kotlin/kotlinx.coroutines/blob/master/LICENSE.txt"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
Apache license 2.0
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a
|
|
||||||
href="https://github.com/Kotlin/kotlinx.coroutines"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
repo
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>slf4j</p>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a
|
|
||||||
href="https://github.com/qos-ch/slf4j/blob/master/LICENSE.txt"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
MIT license
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a href="https://www.slf4j.org/" target="_blank">
|
|
||||||
website
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>Exposed</p>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a href="https://github.com/JetBrains/Exposed/blob/main/LICENSE.txt">
|
|
||||||
Apache license 2.0
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a href="https://github.com/JetBrains/Exposed" target="_blank">
|
|
||||||
repo
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>Krontab</p>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a
|
|
||||||
href="https://github.com/InsanusMokrassar/krontab/blob/master/LICENSE"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
Apache license 2.0
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a
|
|
||||||
href="https://github.com/InsanusMokrassar/krontab"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
repo
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>Splatoon3.ink</p>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a
|
|
||||||
href="https://github.com/misenhower/splatoon3.ink/blob/main/license.md"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
MIT License
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a href="https://splatoon3.ink/" target="_blank">
|
|
||||||
website
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</section>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default acknowledgements;
|
|
|
@ -1,4 +0,0 @@
|
||||||
import { SolidAuth } from "@auth/solid-start"
|
|
||||||
import { authOptions } from "~/server/auth"
|
|
||||||
|
|
||||||
export const { GET, POST } = SolidAuth(authOptions)
|
|
|
@ -1,18 +1,14 @@
|
||||||
import { getSession } from "@auth/solid-start";
|
import { useLocation, useNavigate, useParams } from "@solidjs/router";
|
||||||
import { faToggleOff, faToggleOn } from "@fortawesome/pro-regular-svg-icons";
|
|
||||||
import { useNavigate, useParams } from "@solidjs/router";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import createClient from "openapi-fetch";
|
import {
|
||||||
import { Index, createEffect, createResource, createSignal } from "solid-js";
|
For,
|
||||||
|
Index,
|
||||||
|
createEffect,
|
||||||
|
createResource,
|
||||||
|
createSignal,
|
||||||
|
} from "solid-js";
|
||||||
import { createStore } from "solid-js/store";
|
import { createStore } from "solid-js/store";
|
||||||
import { getRequestEvent } from "solid-js/web";
|
|
||||||
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon";
|
|
||||||
import Layout from "~/components/Layout";
|
import Layout from "~/components/Layout";
|
||||||
import db from "~/drizzle";
|
|
||||||
import { accounts } from "~/drizzle/schema";
|
|
||||||
import { authOptions } from "~/server/auth";
|
|
||||||
import { paths } from "~/types/discord";
|
|
||||||
import "../../styles/pages/config.scss";
|
import "../../styles/pages/config.scss";
|
||||||
|
|
||||||
const guessTZ = () => Intl.DateTimeFormat().resolvedOptions().timeZone;
|
const guessTZ = () => Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
|
@ -23,6 +19,8 @@ const initialValue = (params: ReturnType<typeof useParams>) => ({
|
||||||
id: params.guildId,
|
id: params.guildId,
|
||||||
name: undefined as string | undefined,
|
name: undefined as string | undefined,
|
||||||
icon: undefined as string | null | undefined,
|
icon: undefined as string | null | undefined,
|
||||||
|
channel: "",
|
||||||
|
channels: [] as { id: string; name: string }[],
|
||||||
},
|
},
|
||||||
tzNames: [guessTZ()],
|
tzNames: [guessTZ()],
|
||||||
});
|
});
|
||||||
|
@ -34,101 +32,155 @@ const getPayload = async (
|
||||||
| (ReturnType<typeof initialValue> & { success: true })
|
| (ReturnType<typeof initialValue> & { success: true })
|
||||||
> => {
|
> => {
|
||||||
"use server";
|
"use server";
|
||||||
const event = getRequestEvent();
|
console.log("request for", id);
|
||||||
if (!event) return { success: false, message: "No request event!" };
|
// const event = getRequestEvent();
|
||||||
|
// const location = useLocation();
|
||||||
|
// if (!event) return { success: false, message: "No request event!" };
|
||||||
|
|
||||||
const session = await getSession(event.request, authOptions);
|
// const session = await getSession(event.request, authOptions);
|
||||||
if (!session?.user?.id)
|
// if (!session?.user?.id)
|
||||||
return { success: false, message: "No user with id!" };
|
// return { success: false, message: "No user with id!" };
|
||||||
|
|
||||||
const { DISCORD_ACCESS_TOKEN } = (
|
// const { DISCORD_ACCESS_TOKEN } = (
|
||||||
await db
|
// await db
|
||||||
.selectDistinct({ DISCORD_ACCESS_TOKEN: accounts.access_token })
|
// .selectDistinct({ DISCORD_ACCESS_TOKEN: accounts.access_token })
|
||||||
.from(accounts)
|
// .from(accounts)
|
||||||
.where(eq(accounts.userId, session.user?.id))
|
// .where(eq(accounts.userId, session.user?.id))
|
||||||
.limit(1)
|
// .limit(1)
|
||||||
.execute()
|
// .execute()
|
||||||
)[0];
|
// )[0];
|
||||||
if (!DISCORD_ACCESS_TOKEN)
|
// if (!DISCORD_ACCESS_TOKEN)
|
||||||
return { success: false, message: "No discord access token!" };
|
// return { success: false, message: "No discord access token!" };
|
||||||
|
|
||||||
// const guilds = await fetch("https://discord.com/api/users/@me/guilds", {
|
// const { GET } = createClient<paths>({
|
||||||
|
// baseUrl: "https://discord.com/api/v10",
|
||||||
|
// });
|
||||||
|
// const guildsRequest = await GET("/users/@me/guilds", {
|
||||||
// headers: { Authorization: `Bearer ${DISCORD_ACCESS_TOKEN}` },
|
// headers: { Authorization: `Bearer ${DISCORD_ACCESS_TOKEN}` },
|
||||||
// }).then((res) => res.json());
|
// });
|
||||||
const { GET } = createClient<paths>({
|
// const channelsRequest = await GET("/guilds/{guild_id}/channels", {
|
||||||
baseUrl: "https://discord.com/api/v10",
|
// params: {
|
||||||
});
|
// path: {
|
||||||
const { data: guilds, error } = await GET("/users/@me/guilds", {
|
// guild_id: id,
|
||||||
headers: { Authorization: `Bearer ${DISCORD_ACCESS_TOKEN}` },
|
// },
|
||||||
});
|
// },
|
||||||
|
// headers: { Authorization: `Bot ${import.meta.env.VITE_DISCORD_BOT_TOKEN}` },
|
||||||
|
// });
|
||||||
|
|
||||||
if (error) {
|
// if (guildsRequest.error || channelsRequest.error) {
|
||||||
console.log(error);
|
// console.log(guildsRequest.error, channelsRequest.error, location.pathname);
|
||||||
return { success: false, message: "Error on discord api request!" };
|
// return {
|
||||||
}
|
// success: false,
|
||||||
|
// message: "Error on one of the discord api requests!",
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
const guild = guilds?.find((e) => e.id === id);
|
// const guild = guildsRequest.data?.find((e) => e.id === id);
|
||||||
|
// const guild = [].find((e) => e.id === id);
|
||||||
|
|
||||||
if (!guild)
|
// if (!guild)
|
||||||
return {
|
// return {
|
||||||
success: false,
|
// success: false,
|
||||||
message: "User is in no such guild with requested id!",
|
// message: "User is in no such guild with requested id!",
|
||||||
};
|
// };
|
||||||
if (!(parseInt(guild.permissions) & (1 << 5)))
|
// if (!(parseInt(guild.permissions) & (1 << 5)))
|
||||||
return {
|
// return {
|
||||||
success: false,
|
// success: false,
|
||||||
message:
|
// message:
|
||||||
"User is no MANAGE_GUILD permissions on this guild with requested id!",
|
// "User is no MANAGE_GUILD permissions on this guild with requested id!",
|
||||||
};
|
// };
|
||||||
|
|
||||||
return {
|
// let channels: ReturnType<typeof initialValue>["guild"]["channels"] = [];
|
||||||
success: true,
|
// channelsRequest.data?.forEach((channel) => {
|
||||||
guild: {
|
// if (channel.type !== 0) return;
|
||||||
id: guild.id,
|
// channels.push({
|
||||||
name: guild.name,
|
// id: channel.id,
|
||||||
icon: guild.icon,
|
// name: channel.name,
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
const channels = [
|
||||||
|
{
|
||||||
|
id: "1",
|
||||||
|
name: "first",
|
||||||
},
|
},
|
||||||
// guild: guilds
|
|
||||||
// .filter((e: any) => e.permissions & (1 << 5))
|
{
|
||||||
// .map((e: any) => e.name),
|
id: "2",
|
||||||
tzNames: moment.tz.names(),
|
name: "second",
|
||||||
};
|
},
|
||||||
|
{
|
||||||
|
id: "3",
|
||||||
|
name: "third",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return new Promise((res) => {
|
||||||
|
setTimeout(
|
||||||
|
() =>
|
||||||
|
res({
|
||||||
|
success: true,
|
||||||
|
guild: {
|
||||||
|
id: "598539452343648256",
|
||||||
|
name: "test Server",
|
||||||
|
icon: undefined,
|
||||||
|
channel: "1162917335275950180",
|
||||||
|
channels,
|
||||||
|
},
|
||||||
|
tzNames: moment.tz.names(),
|
||||||
|
}),
|
||||||
|
3000,
|
||||||
|
);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function config() {
|
function config() {
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const navigator = useNavigate();
|
const navigator = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
let timezoneRef: HTMLInputElement;
|
let timezoneRef: HTMLInputElement;
|
||||||
let timePlanningRef: HTMLInputElement;
|
let timePlanningRef: HTMLInputElement;
|
||||||
|
let channelRef: HTMLSelectElement;
|
||||||
let pingableRolesRef: HTMLInputElement;
|
let pingableRolesRef: HTMLInputElement;
|
||||||
|
|
||||||
const [timezone, setTimezone] = createSignal(guessTZ());
|
const [timezone, setTimezone] = createSignal(guessTZ());
|
||||||
const [payload] = createResource(params.guildId, async (id) => {
|
const [payload] = createResource(
|
||||||
const payload = await getPayload(id);
|
params.guildId,
|
||||||
|
async (id) => {
|
||||||
|
const payload = await getPayload(id);
|
||||||
|
|
||||||
if (!payload.success) {
|
if (!payload.success) {
|
||||||
console.log(payload.message, "No success");
|
console.log(location.pathname, payload.message, "No success");
|
||||||
navigator("/config", { replace: false });
|
navigator("/config", { replace: false });
|
||||||
return initialValue(params);
|
return initialValue(params);
|
||||||
}
|
}
|
||||||
return payload;
|
return payload;
|
||||||
});
|
},
|
||||||
const guild = () => payload()?.guild ?? initialValue(params).guild;
|
{ initialValue: initialValue(params) },
|
||||||
const tzNames = () => payload()?.tzNames ?? [];
|
);
|
||||||
|
const guild = () => payload().guild;
|
||||||
|
const tzNames = () => payload().tzNames;
|
||||||
const [config, setConfig] = createStore({
|
const [config, setConfig] = createStore({
|
||||||
features: {
|
features: {
|
||||||
timePlanning: {
|
timePlanning: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
|
channelId: "833442323160891452",
|
||||||
pingableRoles: false,
|
pingableRoles: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
createEffect(() => console.log(payload()));
|
createEffect(() => console.log(payload.loading, payload()));
|
||||||
createEffect(() => console.log("timezone", timezone()));
|
createEffect(() => console.log("timezone", timezone()));
|
||||||
createEffect(() =>
|
createEffect(() =>
|
||||||
console.log("timePlanning.enabled", config.features.timePlanning.enabled),
|
console.log("timePlanning.enabled", config.features.timePlanning.enabled),
|
||||||
);
|
);
|
||||||
|
createEffect(() =>
|
||||||
|
console.log(
|
||||||
|
"timePlanning.channelId",
|
||||||
|
config.features.timePlanning.channelId,
|
||||||
|
),
|
||||||
|
);
|
||||||
createEffect(() =>
|
createEffect(() =>
|
||||||
console.log(
|
console.log(
|
||||||
"timePlanning.pingableRoles",
|
"timePlanning.pingableRoles",
|
||||||
|
@ -136,14 +188,28 @@ function config() {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
createEffect(() => (timezoneRef.value = timezone()));
|
createEffect(() => {
|
||||||
createEffect(
|
timezoneRef.value = timezone();
|
||||||
() => (timePlanningRef.checked = config.features.timePlanning.enabled),
|
});
|
||||||
);
|
createEffect(() => {
|
||||||
createEffect(
|
timePlanningRef.checked = config.features.timePlanning.enabled;
|
||||||
() =>
|
});
|
||||||
(pingableRolesRef.checked = config.features.timePlanning.pingableRoles),
|
createEffect(() => {
|
||||||
);
|
const channelId = payload().guild.channel;
|
||||||
|
setConfig("features", "timePlanning", "channelId", channelId);
|
||||||
|
console.log(channelId, payload());
|
||||||
|
if (
|
||||||
|
!channelRef ||
|
||||||
|
!channelId ||
|
||||||
|
!payload().guild.channels.find((e) => e.id === channelId)
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
channelRef.value = channelId;
|
||||||
|
});
|
||||||
|
createEffect(() => {
|
||||||
|
if (!pingableRolesRef) return;
|
||||||
|
pingableRolesRef.checked = config.features.timePlanning.pingableRoles;
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout site="config">
|
<Layout site="config">
|
||||||
|
@ -154,14 +220,15 @@ function config() {
|
||||||
<img
|
<img
|
||||||
class="guildpfp"
|
class="guildpfp"
|
||||||
src={
|
src={
|
||||||
guild()?.icon
|
guild().icon
|
||||||
? `https://cdn.discordapp.com/icons/${guild()?.id}/${guild()
|
? `https://cdn.discordapp.com/icons/${guild().id}/${
|
||||||
?.icon}.webp?size=240`
|
guild().icon
|
||||||
|
}.webp?size=240`
|
||||||
: "https://cdn.discordapp.com/icons/1040502664506646548/bb5a51c4659cf47bdd942bb11e974da7.webp?size=240"
|
: "https://cdn.discordapp.com/icons/1040502664506646548/bb5a51c4659cf47bdd942bb11e974da7.webp?size=240"
|
||||||
}
|
}
|
||||||
alt="Server pfp"
|
alt="Server pfp"
|
||||||
/>
|
/>
|
||||||
<h1>{guild()?.name ?? "li'l Judds home base"}</h1>
|
<h1>{guild().name}</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -200,12 +267,12 @@ function config() {
|
||||||
<p>Configure the features of the bot</p>
|
<p>Configure the features of the bot</p>
|
||||||
<label for="timePlanning" class="flex-row">
|
<label for="timePlanning" class="flex-row">
|
||||||
<p>Time Planning </p>
|
<p>Time Planning </p>
|
||||||
<FontAwesomeIcon
|
{/* <FontAwesomeIcon
|
||||||
icon={
|
icon={
|
||||||
config.features.timePlanning.enabled ? faToggleOn : faToggleOff
|
config.features.timePlanning.enabled ? faToggleOn : faToggleOff
|
||||||
}
|
}
|
||||||
size="xl"
|
size="xl"
|
||||||
/>
|
/> */}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
hidden
|
hidden
|
||||||
|
@ -222,25 +289,41 @@ function config() {
|
||||||
>
|
>
|
||||||
<div class="flex-row">
|
<div class="flex-row">
|
||||||
<label>Target channel:</label>
|
<label>Target channel:</label>
|
||||||
<select value={timezone()}>
|
<select
|
||||||
<optgroup label="--Select a Channel--">
|
ref={channelRef!}
|
||||||
<Index each={tzNames()}>
|
onInput={(e) =>
|
||||||
{(channel) => <option>{channel()}</option>}
|
setConfig(
|
||||||
</Index>
|
"features",
|
||||||
</optgroup>
|
"timePlanning",
|
||||||
|
"channelId",
|
||||||
|
e.target.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
disabled={!!config.features.timePlanning.channelId}
|
||||||
|
value=""
|
||||||
|
>
|
||||||
|
--Select a Channel--
|
||||||
|
</option>
|
||||||
|
<For each={guild().channels}>
|
||||||
|
{(channel) => (
|
||||||
|
<option value={channel.id}>{channel.name}</option>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-row">
|
<div class="flex-row">
|
||||||
<label for="pingableRoles" class="flex-row">
|
<label for="pingableRoles" class="flex-row">
|
||||||
<p>Enable pingable Roles:</p>
|
<p>Enable pingable Roles:</p>
|
||||||
<FontAwesomeIcon
|
{/* <FontAwesomeIcon
|
||||||
icon={
|
icon={
|
||||||
config.features.timePlanning.pingableRoles
|
config.features.timePlanning.pingableRoles
|
||||||
? faToggleOn
|
? faToggleOn
|
||||||
: faToggleOff
|
: faToggleOff
|
||||||
}
|
}
|
||||||
size="xl"
|
size="xl"
|
||||||
/>
|
/> */}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
hidden
|
hidden
|
||||||
|
|
|
@ -1,121 +1,121 @@
|
||||||
import { getSession } from "@auth/solid-start";
|
// import {
|
||||||
import {
|
// faBadgeCheck,
|
||||||
faBadgeCheck,
|
// faCircleExclamation,
|
||||||
faCircleExclamation,
|
// faPlus,
|
||||||
faPlus,
|
// } from "@fortawesome/pro-regular-svg-icons";
|
||||||
} from "@fortawesome/pro-regular-svg-icons";
|
|
||||||
import { useNavigate } from "@solidjs/router";
|
|
||||||
import { eq } from "drizzle-orm";
|
|
||||||
import createClient from "openapi-fetch";
|
|
||||||
import { For, createResource } from "solid-js";
|
|
||||||
import { getRequestEvent } from "solid-js/web";
|
|
||||||
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon";
|
|
||||||
import Layout from "~/components/Layout";
|
import Layout from "~/components/Layout";
|
||||||
import db from "~/drizzle";
|
|
||||||
import { accounts } from "~/drizzle/schema";
|
|
||||||
import { authOptions } from "~/server/auth";
|
|
||||||
import { paths } from "~/types/discord";
|
|
||||||
import "../../styles/pages/config.scss";
|
import "../../styles/pages/config.scss";
|
||||||
|
|
||||||
const initialValue = () => ({
|
// const initialValue = () => ({
|
||||||
success: null as boolean | null,
|
// success: null as boolean | null,
|
||||||
guilds: [] as {
|
// guilds: [] as {
|
||||||
id: string;
|
// id: string;
|
||||||
name: string;
|
// name: string;
|
||||||
icon: string | null | undefined;
|
// icon: string | null | undefined;
|
||||||
}[],
|
// }[],
|
||||||
});
|
// });
|
||||||
|
|
||||||
const getPayload = async (): Promise<
|
// const getPayload = async (): Promise<
|
||||||
| { success: false; message: string }
|
// | { success: false; message: string }
|
||||||
| (ReturnType<typeof initialValue> & { success: true })
|
// | (ReturnType<typeof initialValue> & { success: true })
|
||||||
> => {
|
// > => {
|
||||||
("use server");
|
// "use server";
|
||||||
const event = getRequestEvent();
|
// const location = useLocation();
|
||||||
if (!event) return { success: false, message: "No request event!" };
|
// const event = getRequestEvent();
|
||||||
|
// if (!event) return { success: false, message: "No request event!" };
|
||||||
|
|
||||||
const session = await getSession(event.request, authOptions);
|
// const session = await getSession(event.request, authOptions);
|
||||||
if (!session?.user?.id)
|
// if (!session?.user?.id)
|
||||||
return { success: false, message: "No user with id!" };
|
// return { success: false, message: "No user with id!" };
|
||||||
|
|
||||||
const { DISCORD_ACCESS_TOKEN } = (
|
// const { DISCORD_ACCESS_TOKEN } = (
|
||||||
await db
|
// await db
|
||||||
.selectDistinct({ DISCORD_ACCESS_TOKEN: accounts.access_token })
|
// .selectDistinct({ DISCORD_ACCESS_TOKEN: accounts.access_token })
|
||||||
.from(accounts)
|
// .from(accounts)
|
||||||
.where(eq(accounts.userId, session.user?.id))
|
// .where(eq(accounts.userId, session.user?.id))
|
||||||
.limit(1)
|
// .limit(1)
|
||||||
.execute()
|
// .execute()
|
||||||
)[0];
|
// )[0];
|
||||||
if (!DISCORD_ACCESS_TOKEN)
|
// if (!DISCORD_ACCESS_TOKEN)
|
||||||
return { success: false, message: "No discord access token!" };
|
// return { success: false, message: "No discord access token!" };
|
||||||
|
|
||||||
const { GET } = createClient<paths>({
|
// const { GET } = createClient<paths>({
|
||||||
baseUrl: "https://discord.com/api/v10",
|
// baseUrl: "https://discord.com/api/v10",
|
||||||
});
|
// });
|
||||||
const { data: guilds, error } = await GET("/users/@me/guilds", {
|
// const { data: guilds, error } = await GET("/users/@me/guilds", {
|
||||||
headers: { Authorization: `Bearer ${DISCORD_ACCESS_TOKEN}` },
|
// headers: { Authorization: `Bearer ${DISCORD_ACCESS_TOKEN}` },
|
||||||
});
|
// });
|
||||||
|
|
||||||
console.log("guilds", guilds);
|
// console.log("guilds", guilds, location.pathname);
|
||||||
|
|
||||||
if (error) {
|
// if (error) {
|
||||||
console.log(error);
|
// console.log(error, location.pathname);
|
||||||
return { success: false, message: "Error on discord api request!" };
|
// return { success: false, message: "Error on discord api request!" };
|
||||||
}
|
// }
|
||||||
|
|
||||||
return {
|
// return {
|
||||||
success: true,
|
// success: true,
|
||||||
guilds:
|
// guilds:
|
||||||
guilds
|
// guilds
|
||||||
?.filter((e) => parseInt(e.permissions) & (1 << 5))
|
// ?.filter((e) => parseInt(e.permissions) & (1 << 5))
|
||||||
.map(({ id, name, icon }) => ({ id, name, icon })) ?? [],
|
// .map(({ id, name, icon }) => ({ id, name, icon })) ?? [],
|
||||||
};
|
// };
|
||||||
};
|
// };
|
||||||
|
|
||||||
function index() {
|
function index() {
|
||||||
const navigator = useNavigate();
|
// const navigator = useNavigate();
|
||||||
|
// const location = useLocation();
|
||||||
|
|
||||||
const [payload] = createResource(async () => {
|
// const [payload] = createResource(async () => {
|
||||||
const payload = await getPayload();
|
// const payload = await getPayload();
|
||||||
|
|
||||||
if (!payload.success) {
|
// if (!payload.success) {
|
||||||
console.log(payload.message, "No success");
|
// console.log(location.pathname, payload.message, "No success");
|
||||||
navigator("/", { replace: false });
|
// navigator("/", { replace: false });
|
||||||
return initialValue();
|
// return initialValue();
|
||||||
}
|
// }
|
||||||
console.log("success");
|
// console.log(location.pathname, "success");
|
||||||
return payload;
|
// return payload;
|
||||||
});
|
// });
|
||||||
|
// createEffect(() => console.log(payload()?.guilds, payload()?.guilds.length));
|
||||||
|
// createRenderEffect(() =>
|
||||||
|
// console.log(payload()?.guilds, payload()?.guilds.length),
|
||||||
|
// );
|
||||||
|
|
||||||
const icons = [faPlus, faCircleExclamation, faBadgeCheck];
|
// const icons = [faPlus, faCircleExclamation, faBadgeCheck];
|
||||||
const colors = [undefined, "orange", "green"];
|
// const colors = [undefined, "orange", "green"];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout site="config">
|
<Layout site="config">
|
||||||
<h3 class="text-center">Configure li'l Judd in</h3>
|
<h3 class="text-center">Configure li'l Judd in</h3>
|
||||||
<div>
|
<div>
|
||||||
<For each={payload()?.guilds ?? []}>
|
{/* <Suspense>
|
||||||
{(guild, i) => (
|
<For each={payload()?.guilds}>
|
||||||
<a href={`/config/${guild.id}`} class="flex-row centered">
|
{(guild, i) => {
|
||||||
<img
|
return (
|
||||||
class="guildpfp"
|
<a
|
||||||
src={
|
href={
|
||||||
guild.icon
|
i() % 3 === 0
|
||||||
? `https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.webp?size=240`
|
? `/config/${guild.id}`
|
||||||
: "https://cdn.discordapp.com/icons/1040502664506646548/bb5a51c4659cf47bdd942bb11e974da7.webp?size=240"
|
: `https://discord.com/api/oauth2/authorize?client_id=${import.meta.env.VITE_DISCORD_CLIENT_ID}&permissions=${import.meta.env.VITE_DISCORD_BOT_PERMISSIONS}&scope=bot&guild_id=${guild.id}`
|
||||||
}
|
}
|
||||||
alt="Server pfp"
|
class="flex-row centered"
|
||||||
/>
|
>
|
||||||
<h1>{guild.name}</h1>
|
<img
|
||||||
<FontAwesomeIcon
|
class="guildpfp"
|
||||||
// beat={i() % 3 === 1}
|
src={
|
||||||
color={colors[i() % 3]}
|
guild.icon
|
||||||
icon={icons[i() % 3]}
|
? `https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.webp?size=240`
|
||||||
size="xl"
|
: "https://cdn.discordapp.com/icons/1040502664506646548/bb5a51c4659cf47bdd942bb11e974da7.webp?size=240"
|
||||||
/>
|
}
|
||||||
</a>
|
alt="Server pfp"
|
||||||
)}
|
/>
|
||||||
</For>
|
<h1>{guild.name}</h1>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</For>
|
||||||
|
</Suspense> */}
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/contact.scss";
|
|
||||||
|
|
||||||
function contact() {
|
|
||||||
return (
|
|
||||||
<Layout site="contact">
|
|
||||||
<h1>Contact</h1>
|
|
||||||
<section>
|
|
||||||
<a href="mailto:contact@moonleay.net" target="_blank">
|
|
||||||
<img src="/assets/icons/email.svg" alt="Email" />
|
|
||||||
contact@moonleay.net
|
|
||||||
</a>
|
|
||||||
<a href="https://discord.com/users/372703841151614976" target="_blank">
|
|
||||||
<img src="/assets/icons/discord.svg" alt="Discord" />
|
|
||||||
@moonleay
|
|
||||||
</a>
|
|
||||||
<a href="https://discord.gg/HTZRktfH4A" target="_blank">
|
|
||||||
<img src="/assets/icons/discord.svg" alt="discord" />
|
|
||||||
li'l Judd's home base
|
|
||||||
</a>
|
|
||||||
</section>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default contact;
|
|
|
@ -1,51 +0,0 @@
|
||||||
import ImageSection from "~/components/ImageSection";
|
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/features.scss";
|
|
||||||
|
|
||||||
function features() {
|
|
||||||
return (
|
|
||||||
<Layout site="features">
|
|
||||||
<h1>Features</h1>
|
|
||||||
<div class="gridlayout">
|
|
||||||
<ImageSection
|
|
||||||
imgUrl="/assets/screenshots/timeplanner.png"
|
|
||||||
imgAlt="Screenshot of the time planning feature of li'l Judd"
|
|
||||||
title="Time Planning and Management"
|
|
||||||
description="Helps you to see on which days your fellow team mates are available."
|
|
||||||
note="The bot can send these planning messages every monday at 3AM. Members can click the buttons on each message to communicate, if they have time on that day."
|
|
||||||
/>
|
|
||||||
<ImageSection
|
|
||||||
imgUrl="/assets/screenshots/matchplanner.png"
|
|
||||||
imgAlt="Screenshot of the match planning feature of li'l Judd"
|
|
||||||
title="Match Planner"
|
|
||||||
description="Make sure that you know when your next match is and who will participate."
|
|
||||||
note="The bot can send these planning messages, when the command /match is used. Members can click the buttons on each message to communicate, if they will participate in the match. Participating members will get a role until the match has started."
|
|
||||||
/>
|
|
||||||
<ImageSection
|
|
||||||
imgUrl="/assets/screenshots/notifs.png"
|
|
||||||
imgAlt="Screenshot of the notification feature of li'l Judd"
|
|
||||||
title="Notifications"
|
|
||||||
description="Make sure that you and your team members vote in the Time Planner."
|
|
||||||
note="The bot can add roles. The first one gets pinged, when the time planner sends the messages, the other one gets assigned to the available members of the day, so that it is possible to ping all available people."
|
|
||||||
/>
|
|
||||||
<ImageSection
|
|
||||||
imgUrl="/assets/screenshots/rotationstatus.png"
|
|
||||||
imgAlt="Screenshot of the current x map rotation in li'l Judd's status"
|
|
||||||
title="Rotation Status"
|
|
||||||
description="Li'l Judd can show you the current map rotation in his status."
|
|
||||||
note="The bot cycles through the current map and mode rotation. It updates every few seconds."
|
|
||||||
/>
|
|
||||||
<ImageSection
|
|
||||||
span
|
|
||||||
imgUrl="/assets/screenshots/unknown.png"
|
|
||||||
imgAlt="A Question Mark"
|
|
||||||
title="More to come.."
|
|
||||||
description="The bot is still in development. More features will be added."
|
|
||||||
note="If you have a specific feature request, you can contact me on Discord: @moonleay or email: contact at moonleay dot net"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default features;
|
|
|
@ -1,62 +0,0 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/how-do-i.scss";
|
|
||||||
|
|
||||||
function howDoI() {
|
|
||||||
return (
|
|
||||||
<Layout site="how-do-i">
|
|
||||||
<h1>How do I...?</h1>
|
|
||||||
<section>
|
|
||||||
<h2>.. enable / disable certain features?</h2>
|
|
||||||
<p>
|
|
||||||
Features can be enabled and disables using the <code>/feature</code>
|
|
||||||
command.
|
|
||||||
<br />
|
|
||||||
Example:
|
|
||||||
</p>
|
|
||||||
<div class="imgwrapper">
|
|
||||||
<img
|
|
||||||
class="desktop"
|
|
||||||
src="/assets/screenshots/featureexample.png"
|
|
||||||
alt="A screenshot of the example in Discord."
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
class="mobile"
|
|
||||||
src="/assets/screenshots/featureexamplemobile.png"
|
|
||||||
alt="A screenshot of the example in Discord."
|
|
||||||
/>
|
|
||||||
{/* <p><code>/feature feature:Time Planning Feature set:Enable channel:#ich-kann-heute</code></p> */}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>.. create a match?</h2>
|
|
||||||
<p>
|
|
||||||
You can create a match time using the <code>/match</code> command.
|
|
||||||
<br />
|
|
||||||
Example:
|
|
||||||
</p>
|
|
||||||
<div class="imgwrapper">
|
|
||||||
<img
|
|
||||||
class="desktop"
|
|
||||||
src="/assets/screenshots/matchexample.png"
|
|
||||||
alt="A screenshot of the example in Discord."
|
|
||||||
/>
|
|
||||||
<img
|
|
||||||
class="mobile"
|
|
||||||
src="/assets/screenshots/matchexamplemobile.png"
|
|
||||||
alt="A screenshot of the example in Discord."
|
|
||||||
/>
|
|
||||||
{/* <p><code>/match match:Ladder Match timestamp:24.12.2069 04:20 opponent:Forbidden</code></p> */}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="note">
|
|
||||||
<p>
|
|
||||||
Is something missing here?
|
|
||||||
<br />
|
|
||||||
Please <a href="/contact">contact me</a>!
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default howDoI;
|
|
|
@ -1,62 +0,0 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/imprint.scss";
|
|
||||||
|
|
||||||
function imprint() {
|
|
||||||
return (
|
|
||||||
<Layout site="imprint">
|
|
||||||
<section>
|
|
||||||
<h1>Imprint</h1>
|
|
||||||
<section>
|
|
||||||
<a href="/contact">
|
|
||||||
<h2>Contact me</h2>
|
|
||||||
</a>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>Liability for contents</h2>
|
|
||||||
<p>
|
|
||||||
As a service provider, we are responsible for our own content on
|
|
||||||
these pages in accordance with general legislation pursuant to
|
|
||||||
Section 7 (1) of the German Telemedia Act (TMG). According to §§ 8
|
|
||||||
to 10 TMG, however, we are not obligated as a service provider to
|
|
||||||
monitor transmitted or stored third-party information or to
|
|
||||||
investigate circumstances that indicate illegal activity.
|
|
||||||
Obligations to remove or block the use of information under the
|
|
||||||
general laws remain unaffected. However, liability in this regard is
|
|
||||||
only possible from the point in time at which a concrete
|
|
||||||
infringement of the law becomes known. If we become aware of any
|
|
||||||
such infringements, we will remove the relevant content immediately.
|
|
||||||
</p>
|
|
||||||
<h5>
|
|
||||||
Source:{" "}
|
|
||||||
<a href="https://www.e-recht24.de/impressum-generator.html">
|
|
||||||
eRecht24
|
|
||||||
</a>
|
|
||||||
</h5>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>Liability for links</h2>
|
|
||||||
<p>
|
|
||||||
Our offer contains links to external websites of third parties, on
|
|
||||||
whose contents we have no influence. Therefore, we cannot assume any
|
|
||||||
liability for these external contents. The respective provider or
|
|
||||||
operator of the pages is always responsible for the content of the
|
|
||||||
linked pages. The linked pages were checked for possible legal
|
|
||||||
violations at the time of linking. Illegal contents were not
|
|
||||||
recognizable at the time of linking. However, a permanent control of
|
|
||||||
the contents of the linked pages is not reasonable without concrete
|
|
||||||
evidence of a violation of the law. If we become aware of any
|
|
||||||
infringements, we will remove such links immediately.{" "}
|
|
||||||
</p>
|
|
||||||
<h5>
|
|
||||||
Source:{" "}
|
|
||||||
<a href="https://www.e-recht24.de/impressum-generator.html">
|
|
||||||
eRecht24
|
|
||||||
</a>
|
|
||||||
</h5>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default imprint;
|
|
|
@ -1,178 +0,0 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/privacy-policy.scss";
|
|
||||||
|
|
||||||
function privacyPolicy() {
|
|
||||||
return (
|
|
||||||
<Layout site="privacyPolicy">
|
|
||||||
<div>
|
|
||||||
<h1>Privacy Policy for li'l Judd</h1>
|
|
||||||
<h4>Last updated: 2023-12-05</h4>
|
|
||||||
</div>
|
|
||||||
<section>
|
|
||||||
<h2>1. Introduction</h2>
|
|
||||||
<p>
|
|
||||||
Welcome to li'l Judd! This Privacy Policy explains how we
|
|
||||||
collect, use, disclose, and safeguard your personal information when
|
|
||||||
you use our Discord bot service.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>2. Data Controller</h2>
|
|
||||||
<p>
|
|
||||||
The data controller for the processing of your personal data is
|
|
||||||
moonleay.
|
|
||||||
<br />
|
|
||||||
Please note that "moonleay" is primarily used as a username and may
|
|
||||||
not directly reflect my legal or real-world identity.
|
|
||||||
<br />
|
|
||||||
You can reach me <a href="/contact">here</a>.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>3. Information We Collect</h2>
|
|
||||||
<h3>3.1 Discord User Data</h3>
|
|
||||||
<p>
|
|
||||||
We may collect and process the following (personal) data related to
|
|
||||||
your Discord account & guilds:
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<p>- Discord User ID</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>- Discord username, discriminator and IDs of users</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>- Guild name and ID</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>- Channel names and IDs of channels with active features</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>- Message IDs of the bot messages</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>- Role IDs of created roles</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<h3>3.2 Usage Data</h3>
|
|
||||||
<p>
|
|
||||||
We may collect information on how you interact with our bot, including
|
|
||||||
but not limited to:
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<p>- Commands issued</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>- Server and channel information</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>- Timestamps of interactions</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>4. How we use your Information</h2>
|
|
||||||
<p>We process your personal data for the following purposes:</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<p>- To provide and maintain the bot service.</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>- To improve, customize, and optimize our bot.</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>- To respond to your requests, comments, or inquiries.</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>- To comply with legal obligations.</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>5. Legal Basis for Processing</h2>
|
|
||||||
<p>We process your personal data on the following legal bases:</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
- Consent: You have given your consent for the processing of your
|
|
||||||
personal data for one or more specific purposes.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
- Performance of a contract: The processing is necessary for the
|
|
||||||
performance of the agreement between you and us.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>6. Data Sharing</h2>
|
|
||||||
<p>
|
|
||||||
We do not sell, trade, or otherwise transfer your personal information
|
|
||||||
to third parties. However, we may share your information with:
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
- Third-party service providers involved in the operation and
|
|
||||||
maintenance of the bot.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>7. Data Security</h2>
|
|
||||||
<p>
|
|
||||||
We implement reasonable security measures to protect your personal
|
|
||||||
information from unauthorized access, disclosure, alteration, and
|
|
||||||
destruction.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>8. Your Rights</h2>
|
|
||||||
<p>You have the following rights regarding your personal data:</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
- Right to withdraw consent: You have the right to withdraw your
|
|
||||||
consent at any time. You can do this by contacting us at
|
|
||||||
contact@moonleay.net.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
- Right to rectification: You can request corrections to
|
|
||||||
inaccurate or incomplete information.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
- Right to erasure: You can request the deletion of your personal
|
|
||||||
data.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>9. Changes to this Privacy Policy</h2>
|
|
||||||
<p>
|
|
||||||
We may update this Privacy Policy to reflect changes in our practices.
|
|
||||||
The updated version will be posted on
|
|
||||||
https://liljudd.ink/privacy-policy.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<h2>10. Contact Information</h2>
|
|
||||||
<p>
|
|
||||||
If you have any questions or concerns about this Privacy Policy,
|
|
||||||
please contact us at contact@moonleay.net.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default privacyPolicy;
|
|
|
@ -1,55 +0,0 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/stack.scss";
|
|
||||||
|
|
||||||
function stack() {
|
|
||||||
return (
|
|
||||||
<Layout site="stack">
|
|
||||||
<h1>The Stack</h1>
|
|
||||||
<section>
|
|
||||||
<img src="/assets/logos/kotlin.svg" alt="Kotlin 'K' logo" />
|
|
||||||
<div class="stackgrid_3 stackitm">
|
|
||||||
<h1>The Kotlin programming language</h1>
|
|
||||||
<p>
|
|
||||||
A programming language, which runs in the JVM. Also my main
|
|
||||||
language.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<img src="/assets/logos/kord.png" alt="The Kord logo" />
|
|
||||||
<div class="stackgrid_3 stackitm">
|
|
||||||
<h1>The Kord library</h1>
|
|
||||||
<p>A Kotlin library for creating Discord bots. Pretty bare bones.</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<img
|
|
||||||
src="/assets/logos/kordextensions.png"
|
|
||||||
alt="The Kord-Extensions logo"
|
|
||||||
/>
|
|
||||||
<div class="stackgrid_3 stackitm">
|
|
||||||
<h1>The Kord Extensions library</h1>
|
|
||||||
<p>A Kotlin library to improve the Kord experience.</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<img src="/assets/logos/pgelephant.png" alt="The PostgreSQL elephant" />
|
|
||||||
<div class="stackgrid_3 stackitm">
|
|
||||||
<h1>The PostgreSQL database</h1>
|
|
||||||
<p>
|
|
||||||
A fast and reliable database. Also something, which I already used
|
|
||||||
beforehand.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section class="stack-note">
|
|
||||||
<p>
|
|
||||||
To view all used libraries and their licenses, check the{" "}
|
|
||||||
<a href="/acknowledgements">Acknowledgements</a>.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default stack;
|
|
|
@ -1,95 +0,0 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/terms-of-service.scss";
|
|
||||||
|
|
||||||
function termsOfService() {
|
|
||||||
return (
|
|
||||||
<Layout site="termsOfService">
|
|
||||||
<h1>Terms of Service</h1>
|
|
||||||
<div>
|
|
||||||
<h2>Usage Agreement</h2>
|
|
||||||
<p>
|
|
||||||
By inviting the bot and using its features (commands, planning system)
|
|
||||||
are you agreeing to the below mentioned Terms and Privacy Policy
|
|
||||||
(Policy) of the bot.
|
|
||||||
<br />
|
|
||||||
You acknowledge that you have the privilege to use the bot freely on
|
|
||||||
any Discord Server (Server) you share with it, that you can invite it
|
|
||||||
to any Server that you have "Manage Server" rights for and that this
|
|
||||||
privilege might get revoked for you, if you're subject of breaking the
|
|
||||||
terms and/or policy of this bot, or the{" "}
|
|
||||||
<a href="https://discord.com/terms" target="_blank">
|
|
||||||
Terms of Service
|
|
||||||
</a>
|
|
||||||
,{" "}
|
|
||||||
<a href="https://discord.com/privacy" target="_blank">
|
|
||||||
Privacy Policy
|
|
||||||
</a>{" "}
|
|
||||||
and/or{" "}
|
|
||||||
<a href="https://discord.com/guidelines" target="_blank">
|
|
||||||
Community Guidelines
|
|
||||||
</a>{" "}
|
|
||||||
of{" "}
|
|
||||||
<a href="https://discord.com/" target="_blank">
|
|
||||||
Discord Inc
|
|
||||||
</a>
|
|
||||||
.<br />
|
|
||||||
Through Inviting the bot may it collect specific data as described in
|
|
||||||
its Policy.
|
|
||||||
<br />
|
|
||||||
The intended usage of this data is for core functionalities of the bot
|
|
||||||
such as command handling, guild-specific settings and the
|
|
||||||
time-planning system.
|
|
||||||
<br />
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h2>Intended Age</h2>
|
|
||||||
<p>
|
|
||||||
The bot may not be used by individuals under the minimal age described
|
|
||||||
in Discord's Terms of Service.
|
|
||||||
<br />
|
|
||||||
Doing so will be seen as a violation of these terms and will result in
|
|
||||||
a removal of the bot from any servers you own.
|
|
||||||
<br />
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h2>Affiliation</h2>
|
|
||||||
<p>
|
|
||||||
The Bot is not affiliated with, supported or made by Discord Inc.
|
|
||||||
<br />
|
|
||||||
Any direct connection to Discord or any of its Trademark objects is
|
|
||||||
purely coincidental. We do not claim to have the copyright ownership
|
|
||||||
of any of Discord's assets, trademarks or other intellectual property.
|
|
||||||
<br />
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h2>Liability</h2>
|
|
||||||
<p>
|
|
||||||
The owner of the bot may not be made liable for individuals breaking
|
|
||||||
these Terms at any given time.
|
|
||||||
<br />
|
|
||||||
He has faith in the end users being truthfull about their information
|
|
||||||
and not misusing this bot or the services of Discord Inc in a
|
|
||||||
malicious way.
|
|
||||||
<br />
|
|
||||||
We reserve the right to update these terms at our own discretion,
|
|
||||||
giving you a 1-Week (7 days) period to opt out of these terms if
|
|
||||||
you're not agreeing with the new changes. You may opt out by Removing
|
|
||||||
the bot from any Server you have the rights for.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h2>Contact</h2>
|
|
||||||
<p>
|
|
||||||
People may get in contact through e-mail at contact@moonleay.net, or
|
|
||||||
through the official Support Discord of the Bot. Other ways of support
|
|
||||||
may be provided but aren't guaranteed.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default termsOfService;
|
|
4
src/types/env.d.ts
vendored
4
src/types/env.d.ts
vendored
|
@ -1,9 +1,10 @@
|
||||||
/// <reference types="vinxi/client" />
|
/// <reference types="vinxi/client" />
|
||||||
|
|
||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
readonly VITE_DISCORD_CLIENT: string;
|
readonly VITE_DISCORD_CLIENT_ID: string;
|
||||||
readonly VITE_DISCORD_CLIENT_SECRET: string;
|
readonly VITE_DISCORD_CLIENT_SECRET: string;
|
||||||
readonly VITE_DISCORD_BOT_TOKEN: string;
|
readonly VITE_DISCORD_BOT_TOKEN: string;
|
||||||
|
readonly VITE_DISCORD_BOT_PERMISSIONS: string;
|
||||||
|
|
||||||
readonly VITE_AUTH_SECRET: string;
|
readonly VITE_AUTH_SECRET: string;
|
||||||
readonly VITE_AUTH_REDIRECT_PROXY_URL: string | undefined;
|
readonly VITE_AUTH_REDIRECT_PROXY_URL: string | undefined;
|
||||||
|
@ -11,6 +12,7 @@ interface ImportMetaEnv {
|
||||||
readonly VITE_DATABASE_URL: string;
|
readonly VITE_DATABASE_URL: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
readonly env: ImportMetaEnv;
|
readonly env: ImportMetaEnv;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue