Compare commits
No commits in common. "c3bf31b3d4b806a303c4c2250ae4d47e4a444acf" and "712affc83d6fa7ab1765e17edb2a0bab2056d4ca" have entirely different histories.
c3bf31b3d4
...
712affc83d
43 changed files with 3551 additions and 10944 deletions
|
@ -13,11 +13,6 @@ Authorization: Bearer {{$dotenv DISCORD_ACCESS_TOKEN}}
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
GET https://discord.com/api/guilds/{{$dotenv DISCORD_GUILD_ID}}
|
|
||||||
Authorization: Bot {{$dotenv DISCORD_BOT_TOKEN}}
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
POST https://discord.com/api/oauth2/token/revoke
|
POST https://discord.com/api/oauth2/token/revoke
|
||||||
Content-Type: application/x-www-form-urlencoded
|
Content-Type: application/x-www-form-urlencoded
|
||||||
Authorization: Basic {{$dotenv DISCORD_CLIENT_ID}}:{{$dotenv DISCORD_CLIENT_SECRET}}
|
Authorization: Basic {{$dotenv DISCORD_CLIENT_ID}}:{{$dotenv DISCORD_CLIENT_SECRET}}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import "dotenv/config";
|
import "dotenv/config"
|
||||||
import type { Config } from "drizzle-kit";
|
import type { Config } from "drizzle-kit"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
schema: "./src/drizzle/schema.ts",
|
schema: "./src/drizzle/schema.ts",
|
||||||
|
@ -8,4 +8,4 @@ export default {
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
connectionString: process.env.DATABASE_URL ?? "",
|
connectionString: process.env.DATABASE_URL ?? "",
|
||||||
},
|
},
|
||||||
} satisfies Config;
|
} satisfies Config
|
||||||
|
|
24
package.json
24
package.json
|
@ -7,30 +7,20 @@
|
||||||
"start": "vinxi start",
|
"start": "vinxi start",
|
||||||
"lint": "eslint --fix \"**/*.{ts,tsx,js,jsx}\"",
|
"lint": "eslint --fix \"**/*.{ts,tsx,js,jsx}\"",
|
||||||
"push": "drizzle-kit push:pg",
|
"push": "drizzle-kit push:pg",
|
||||||
"discord-openapi-gen": "pnpm openapi-typescript https://raw.githubusercontent.com/discord/discord-api-spec/main/specs/openapi.json -o ./src/types/discord.d.ts",
|
|
||||||
"liljudd-openapi-gen": "pnpm openapi-typescript ./public/api/specs/liljudd.json -o ./src/types/liljudd.d.ts",
|
|
||||||
"typecheck": "tsc --noEmit --checkJs false --skipLibCheck"
|
"typecheck": "tsc --noEmit --checkJs false --skipLibCheck"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@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",
|
"@solidjs/meta": "^0.29.3",
|
||||||
"@fortawesome/pro-duotone-svg-icons": "^6.5.1",
|
"@solidjs/router": "^0.10.5",
|
||||||
"@fortawesome/pro-light-svg-icons": "^6.5.1",
|
"@solidjs/start": "^0.4.2",
|
||||||
"@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/router": "^0.10.9",
|
|
||||||
"@solidjs/start": "^0.4.9",
|
|
||||||
"drizzle-orm": "^0.29.2",
|
"drizzle-orm": "^0.29.2",
|
||||||
"moment-timezone": "^0.5.44",
|
|
||||||
"openapi-fetch": "^0.8.2",
|
|
||||||
"postgres": "^3.4.3",
|
"postgres": "^3.4.3",
|
||||||
"solid-js": "^1.8.11",
|
"solid-js": "^1.8.7",
|
||||||
"vinxi": "^0.1.2"
|
"solid-start": "^0.3.10",
|
||||||
|
"vinxi": "0.0.62"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^6.17.0",
|
"@typescript-eslint/eslint-plugin": "^6.17.0",
|
||||||
|
@ -40,12 +30,10 @@
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.56.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-solid": "^0.13.1",
|
"eslint-plugin-solid": "^0.13.1",
|
||||||
"openapi-typescript": "^6.7.3",
|
|
||||||
"pg": "^8.11.3",
|
"pg": "^8.11.3",
|
||||||
"prettier": "^3.1.1",
|
"prettier": "^3.1.1",
|
||||||
"prettier-plugin-organize-imports": "^3.2.4",
|
"prettier-plugin-organize-imports": "^3.2.4",
|
||||||
"sass": "^1.69.6",
|
"sass": "^1.69.6",
|
||||||
"typescript": "^5.3.3",
|
|
||||||
"zod": "3.22.4"
|
"zod": "3.22.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
3721
pnpm-lock.yaml
3721
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -1,34 +0,0 @@
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<meta name="description" content="SwaggerUI" />
|
|
||||||
<title>SwaggerUI</title>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="https://unpkg.com/swagger-ui-dist@4.5.0/swagger-ui.css"
|
|
||||||
/>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="swagger-ui"></div>
|
|
||||||
<script
|
|
||||||
src="https://unpkg.com/swagger-ui-dist@4.5.0/swagger-ui-bundle.js"
|
|
||||||
crossorigin
|
|
||||||
></script>
|
|
||||||
<script
|
|
||||||
src="https://unpkg.com/swagger-ui-dist@4.5.0/swagger-ui-standalone-preset.js"
|
|
||||||
crossorigin
|
|
||||||
></script>
|
|
||||||
<script>
|
|
||||||
window.onload = () => {
|
|
||||||
window.ui = SwaggerUIBundle({
|
|
||||||
url: "/api/specs/liljudd.json",
|
|
||||||
dom_id: "#swagger-ui",
|
|
||||||
presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],
|
|
||||||
layout: "StandaloneLayout",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,238 +0,0 @@
|
||||||
{
|
|
||||||
"openapi": "3.0.0",
|
|
||||||
"info": {
|
|
||||||
"title": "li'l Judd - OpenAPI 3.0",
|
|
||||||
"description": "None yet",
|
|
||||||
"termsOfService": "https://liljudd.ink/terms-of-service/",
|
|
||||||
"contact": {
|
|
||||||
"url": "https://liljudd.ink/contact/"
|
|
||||||
},
|
|
||||||
"version": "0.0.0"
|
|
||||||
},
|
|
||||||
"paths": {
|
|
||||||
"/api/config/{guildId}": {
|
|
||||||
"get": {
|
|
||||||
"tags": [
|
|
||||||
"Guild configs"
|
|
||||||
],
|
|
||||||
"summary": "Find guild config by ID",
|
|
||||||
"description": "Returns a single guild config",
|
|
||||||
"operationId": "getGuildById",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "guildId",
|
|
||||||
"in": "path",
|
|
||||||
"description": "ID of guild config to return",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(19)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "successful operation",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/guildConfig"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Invalid ID supplied"
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "Guild not found"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"api_key": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"delete": {
|
|
||||||
"tags": [
|
|
||||||
"Guild configs"
|
|
||||||
],
|
|
||||||
"summary": "Deletes a guild config by ID",
|
|
||||||
"description": "Delete a guild's config",
|
|
||||||
"operationId": "deleteGuildById",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "guildId",
|
|
||||||
"in": "path",
|
|
||||||
"description": "ID of guild config to delete",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(19)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"204": {
|
|
||||||
"description": "successful operation"
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Invalid ID supplied"
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "Guild not found"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"api_key": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/api/tp_messages/{guildId}": {
|
|
||||||
"get": {
|
|
||||||
"tags": [
|
|
||||||
"Time planning messages"
|
|
||||||
],
|
|
||||||
"summary": "Find guild by ID for it's tp_messages",
|
|
||||||
"description": "Returns tp_messages for a guild",
|
|
||||||
"operationId": "getTp_messagesOfGuildById",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"name": "guildId",
|
|
||||||
"in": "path",
|
|
||||||
"description": "ID of guild's tp_messages to return",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(19)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "successful operation",
|
|
||||||
"content": {
|
|
||||||
"application/json": {
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/components/schemas/guildConfig"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"204": {
|
|
||||||
"description": "Time planning not enabled for this guild"
|
|
||||||
},
|
|
||||||
"400": {
|
|
||||||
"description": "Invalid ID supplied"
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"description": "Guild not found"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"api_key": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"components": {
|
|
||||||
"schemas": {
|
|
||||||
"guildConfig": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"guildID": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(19)",
|
|
||||||
"example": "1234567890123456789"
|
|
||||||
},
|
|
||||||
"features": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"time_planning": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"channelID": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(19)",
|
|
||||||
"example": "1234567890123456789"
|
|
||||||
},
|
|
||||||
"cron": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "0 0 1 * * * 60o 1w"
|
|
||||||
},
|
|
||||||
"isAvailableRoleId": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(19)",
|
|
||||||
"example": "1234567890123456789"
|
|
||||||
},
|
|
||||||
"wantsToBeNotifieRoledId": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(19)",
|
|
||||||
"example": "1234567890123456789"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"matches": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/components/schemas/match"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"match": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"channelID": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(19)",
|
|
||||||
"example": "1234567890123456789"
|
|
||||||
},
|
|
||||||
"matchType": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(50)",
|
|
||||||
"example": "Scrim"
|
|
||||||
},
|
|
||||||
"createrId": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(19)",
|
|
||||||
"example": "1234567890123456789"
|
|
||||||
},
|
|
||||||
"roleId": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(19)",
|
|
||||||
"example": "1234567890123456789"
|
|
||||||
},
|
|
||||||
"opponentName": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(100)",
|
|
||||||
"example": "?"
|
|
||||||
},
|
|
||||||
"messsageId": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "varchar(19)",
|
|
||||||
"example": "1234567890123456789"
|
|
||||||
},
|
|
||||||
"cron": {
|
|
||||||
"type": "string",
|
|
||||||
"example": "0 0 1 5 2 2023 60o"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"securitySchemes": {
|
|
||||||
"api_key": {
|
|
||||||
"type": "apiKey",
|
|
||||||
"name": "api_key",
|
|
||||||
"in": "header"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
@ -1,10 +1,12 @@
|
||||||
// @refresh reload
|
// @refresh reload
|
||||||
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";
|
||||||
import { Suspense } from "solid-js";
|
import { Suspense } from "solid-js";
|
||||||
import "./styles/global.scss";
|
import Footer from "./components/Footer";
|
||||||
|
import NavBar from "./components/NavBar";
|
||||||
|
import "./styles/GlobalLayout.css";
|
||||||
|
import "./styles/Layout.scss";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
|
@ -16,8 +18,9 @@ export default function App() {
|
||||||
content="The Splatoon Discord bot with unique features."
|
content="The Splatoon Discord bot with unique features."
|
||||||
/>
|
/>
|
||||||
<Title>li'l Judd - Your competitive Splatoon assistant</Title>
|
<Title>li'l Judd - Your competitive Splatoon assistant</Title>
|
||||||
|
<NavBar />
|
||||||
<Suspense>{props.children}</Suspense>
|
<Suspense>{props.children}</Suspense>
|
||||||
|
<Footer />
|
||||||
</MetaProvider>
|
</MetaProvider>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -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,18 +0,0 @@
|
||||||
import { JSX, Suspense } from "solid-js";
|
|
||||||
import "../styles/Layout.scss";
|
|
||||||
import Footer from "./Footer";
|
|
||||||
import NavBar from "./NavBar";
|
|
||||||
|
|
||||||
function Layout(props: { children: JSX.Element; site: string }) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<NavBar />
|
|
||||||
<div class={props.site}>
|
|
||||||
<Suspense>{props.children}</Suspense>
|
|
||||||
</div>
|
|
||||||
<Footer />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Layout;
|
|
|
@ -1,53 +1,35 @@
|
||||||
import { faCirclePlus } from "@fortawesome/pro-regular-svg-icons";
|
|
||||||
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";
|
|
||||||
|
|
||||||
export function Li(props: {
|
|
||||||
href: string;
|
|
||||||
action?: () => void;
|
|
||||||
name?: string;
|
|
||||||
children?: JSX.Element;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<li class="navElem flex-row thick">
|
|
||||||
<a
|
|
||||||
class="flex-row"
|
|
||||||
href={props.href}
|
|
||||||
onClick={() => props.action && props.action()}
|
|
||||||
>
|
|
||||||
{props.children ?? <></>}
|
|
||||||
<Show when={props.name}>
|
|
||||||
<span>{props.name}</span>
|
|
||||||
</Show>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function NavBar() {
|
function NavBar() {
|
||||||
return (
|
return (
|
||||||
<nav class="flex-row responsive">
|
<nav>
|
||||||
<ul class="flex-row responsive thick">
|
<ul>
|
||||||
<Li href="/" name="li'l Judd">
|
<li class="navElem">
|
||||||
<img src="/assets/logox256.png" alt="The Bots Logo" />
|
<a class="textBx" href="/">
|
||||||
</Li>
|
<img id="logo" src="/assets/logox256.png" alt="The Bots Logo" />
|
||||||
<Li href="/features" name="Features" />
|
li'l Judd
|
||||||
<Li href="/how-do-i" name="How do I...?" />
|
</a>
|
||||||
<Li href="/stack" name="The Stack" />
|
</li>
|
||||||
<Li href="/about" name="About" />
|
<li class="navElem">
|
||||||
</ul>
|
<a href="/features">Features</a>
|
||||||
<ul class="flex-row responsive thick">
|
</li>
|
||||||
<Li
|
<li class="navElem">
|
||||||
|
<a href="/how-do-i">How do I...?</a>
|
||||||
|
</li>
|
||||||
|
<li class="navElem">
|
||||||
|
<a href="/stack">The Stack</a>
|
||||||
|
</li>
|
||||||
|
<li class="navElem">
|
||||||
|
<a href="/about">About</a>
|
||||||
|
</li>
|
||||||
|
<li class="navElem">
|
||||||
|
<a
|
||||||
href="https://discord.com/api/oauth2/authorize?client_id=1024410658973941862&permissions=18977581952080&scope=bot"
|
href="https://discord.com/api/oauth2/authorize?client_id=1024410658973941862&permissions=18977581952080&scope=bot"
|
||||||
name="Invite to your server"
|
target="_blank"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon class="lower" icon={faCirclePlus} size="xl" />
|
Invite to your server
|
||||||
</Li>
|
</a>
|
||||||
<Suspense>
|
</li>
|
||||||
<NavUser />
|
|
||||||
</Suspense>
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
import { getSession } from "@auth/solid-start";
|
|
||||||
import { signIn, signOut } from "@auth/solid-start/client";
|
|
||||||
import {
|
|
||||||
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";
|
|
||||||
|
|
||||||
const initialUser = {
|
|
||||||
id: "",
|
|
||||||
name: null as string | null,
|
|
||||||
email: "",
|
|
||||||
emailVerified: null as Date | null,
|
|
||||||
image: null as string | null,
|
|
||||||
};
|
|
||||||
|
|
||||||
async function getUser() {
|
|
||||||
"use server";
|
|
||||||
|
|
||||||
const event = getRequestEvent();
|
|
||||||
if (!event)
|
|
||||||
return { success: false, message: "No request event!", ...initialUser };
|
|
||||||
|
|
||||||
const session = await getSession(event.request, authOptions);
|
|
||||||
if (!session?.user?.id)
|
|
||||||
return { success: false, message: "No user with id!", ...initialUser };
|
|
||||||
|
|
||||||
const user = (
|
|
||||||
await db
|
|
||||||
.selectDistinct()
|
|
||||||
.from(users)
|
|
||||||
.where(eq(users.id, session.user?.id))
|
|
||||||
.limit(1)
|
|
||||||
.execute()
|
|
||||||
)[0];
|
|
||||||
|
|
||||||
return { success: true, message: "", ...user };
|
|
||||||
}
|
|
||||||
|
|
||||||
function NavUser() {
|
|
||||||
const [user] = createResource(() =>
|
|
||||||
getUser().then((e) => {
|
|
||||||
if (!e.success) console.log(1, e.message);
|
|
||||||
console.log(2, e);
|
|
||||||
return e;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Show
|
|
||||||
when={user()?.id}
|
|
||||||
fallback={
|
|
||||||
<Li
|
|
||||||
href="#"
|
|
||||||
name="Login"
|
|
||||||
action={() => signIn("discord", { callbackUrl: "/config" })}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
class="secondary"
|
|
||||||
icon={faArrowRightToBracket}
|
|
||||||
size="xl"
|
|
||||||
/>
|
|
||||||
</Li>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Li href="/config">
|
|
||||||
<div class="swap lower">
|
|
||||||
<img class="primary" src={user()?.image ?? ""} alt="User pfp" />
|
|
||||||
<FontAwesomeIcon class="secondary" icon={faGear} size="xl" />
|
|
||||||
</div>
|
|
||||||
</Li>
|
|
||||||
<Li href="#" action={() => signOut({ callbackUrl: "/" })}>
|
|
||||||
<FontAwesomeIcon icon={faArrowRightFromBracket} size="xl" />
|
|
||||||
</Li>
|
|
||||||
</Show>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default NavUser;
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { drizzle } from "drizzle-orm/postgres-js";
|
import { drizzle } from "drizzle-orm/postgres-js"
|
||||||
import postgres from "postgres";
|
import postgres from "postgres"
|
||||||
import * as schema from "./schema";
|
import * as schema from "./schema"
|
||||||
|
|
||||||
const queryClient = postgres(import.meta.env.VITE_DATABASE_URL ?? "");
|
const queryClient = postgres(process.env.DATABASE_URL ?? "")
|
||||||
const db = drizzle(queryClient, {
|
const db = drizzle(queryClient, {
|
||||||
schema,
|
schema,
|
||||||
});
|
})
|
||||||
|
|
||||||
export default db;
|
export default db
|
||||||
|
|
|
@ -12,22 +12,23 @@ import {
|
||||||
} from "drizzle-orm/pg-core";
|
} from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
export const users = pgTable("user", {
|
export const users = pgTable("user", {
|
||||||
id: text("id").notNull().primaryKey(),
|
id: text("id").primaryKey(),
|
||||||
name: text("name"),
|
name: text("name"),
|
||||||
email: text("email").notNull(),
|
email: text("email").notNull(),
|
||||||
emailVerified: timestamp("emailVerified", { mode: "date" }),
|
emailVerified: timestamp("email_verified", { mode: "date" }),
|
||||||
image: text("image"),
|
image: text("image"),
|
||||||
|
createdAt: timestamp("created_at").defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const accounts = pgTable(
|
export const accounts = pgTable(
|
||||||
"account",
|
"account",
|
||||||
{
|
{
|
||||||
userId: text("userId")
|
userId: text("user_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => users.id, { onDelete: "cascade" }),
|
.references(() => users.id, { onDelete: "cascade" }),
|
||||||
type: text("type").$type<AdapterAccount["type"]>().notNull(),
|
type: text("type").$type<AdapterAccount["type"]>().notNull(),
|
||||||
provider: text("provider").notNull(),
|
provider: text("provider").notNull(),
|
||||||
providerAccountId: text("providerAccountId").notNull(),
|
providerAccountId: text("provider_account_id").notNull(),
|
||||||
refresh_token: text("refresh_token"),
|
refresh_token: text("refresh_token"),
|
||||||
access_token: text("access_token"),
|
access_token: text("access_token"),
|
||||||
expires_at: integer("expires_at"),
|
expires_at: integer("expires_at"),
|
||||||
|
@ -44,15 +45,15 @@ export const accounts = pgTable(
|
||||||
);
|
);
|
||||||
|
|
||||||
export const sessions = pgTable("session", {
|
export const sessions = pgTable("session", {
|
||||||
sessionToken: text("sessionToken").notNull().primaryKey(),
|
sessionToken: text("session_token").primaryKey(),
|
||||||
userId: text("userId")
|
userId: text("user_id")
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => users.id, { onDelete: "cascade" }),
|
.references(() => users.id, { onDelete: "cascade" }),
|
||||||
expires: timestamp("expires", { mode: "date" }).notNull(),
|
expires: timestamp("expires", { mode: "date" }).notNull(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const verificationTokens = pgTable(
|
export const verificationTokens = pgTable(
|
||||||
"verificationToken",
|
"verification_token",
|
||||||
{
|
{
|
||||||
identifier: text("identifier").notNull(),
|
identifier: text("identifier").notNull(),
|
||||||
token: text("token").notNull(),
|
token: text("token").notNull(),
|
||||||
|
@ -65,14 +66,14 @@ export const verificationTokens = pgTable(
|
||||||
|
|
||||||
export const matchPlannings = pgTable("match_planning", {
|
export const matchPlannings = pgTable("match_planning", {
|
||||||
id: serial("id").primaryKey(),
|
id: serial("id").primaryKey(),
|
||||||
channelId: varchar("channel_id", { length: 20 }).notNull(),
|
channelId: varchar("channel_id", { length: 19 }).notNull(),
|
||||||
matchtype: varchar("match_type", { length: 50 }).notNull(),
|
matchtype: varchar("matchtype", { length: 50 }).notNull(),
|
||||||
createrId: varchar("creater_id", { length: 20 }).notNull(),
|
createrId: varchar("creater_id", { length: 19 }).notNull(),
|
||||||
roleId: varchar("role_id", { length: 20 }).notNull(),
|
roleId: varchar("role_id", { length: 19 }).notNull(),
|
||||||
opponentName: varchar("opponent_name", { length: 100 }).notNull(),
|
opponentName: varchar("opponent_name", { length: 100 }).notNull(),
|
||||||
messageId: varchar("message_id", { length: 20 }).notNull(),
|
messageId: varchar("message_id", { length: 19 }).notNull(),
|
||||||
ts: timestamp("ts").notNull(),
|
plannedFor: timestamp("planned_for", { precision: 3 }).notNull(),
|
||||||
guildId: varchar("guild_id", { length: 20 })
|
guildId: varchar("guild_id", { length: 19 })
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => guilds.id, { onDelete: "cascade" }),
|
.references(() => guilds.id, { onDelete: "cascade" }),
|
||||||
});
|
});
|
||||||
|
@ -85,8 +86,7 @@ export const matchPlanningsRelations = relations(matchPlannings, ({ one }) => ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const guilds = pgTable("guild", {
|
export const guilds = pgTable("guild", {
|
||||||
id: varchar("id", { length: 20 }).primaryKey(),
|
id: varchar("id", { length: 19 }).primaryKey(),
|
||||||
timezone: text("timezone").notNull(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const guildsRelations = relations(guilds, ({ one, many }) => ({
|
export const guildsRelations = relations(guilds, ({ one, many }) => ({
|
||||||
|
@ -99,42 +99,41 @@ export const guildsRelations = relations(guilds, ({ one, many }) => ({
|
||||||
|
|
||||||
export const timePlannings = pgTable("time_planning", {
|
export const timePlannings = pgTable("time_planning", {
|
||||||
id: serial("id").primaryKey(),
|
id: serial("id").primaryKey(),
|
||||||
guildId: varchar("guild_id", { length: 20 })
|
guildId: varchar("guild_id", { length: 19 })
|
||||||
.notNull()
|
|
||||||
.unique()
|
|
||||||
.references(() => guilds.id, {
|
.references(() => guilds.id, {
|
||||||
onDelete: "cascade",
|
onDelete: "cascade",
|
||||||
}),
|
})
|
||||||
channelId: varchar("channel_id", { length: 20 }).notNull(),
|
.notNull()
|
||||||
target_interval: smallint("target_interval").notNull(),
|
.unique(),
|
||||||
isAvailableRoleId: varchar("is_available_role_id", { length: 20 }),
|
channelId: varchar("channel_id", { length: 19 }).notNull(),
|
||||||
|
targetWeekday: smallint("target_weekday").notNull(),
|
||||||
|
targetHour: smallint("target_hour").notNull(),
|
||||||
|
targetMinute: smallint("target_minute").notNull(),
|
||||||
|
isAvailableRoleId: varchar("is_available_role_id", { length: 19 }),
|
||||||
wantsToBeNotifieRoledId: varchar("wants_to_be_notified_role_id", {
|
wantsToBeNotifieRoledId: varchar("wants_to_be_notified_role_id", {
|
||||||
length: 20,
|
length: 19,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const timePlanningsRelations = relations(
|
export const timePlanningsRelations = relations(
|
||||||
timePlannings,
|
timePlannings,
|
||||||
({ one, many }) => ({
|
({ one, many }) => ({
|
||||||
guild: one(guilds, {
|
guild: one(tpMessages),
|
||||||
fields: [timePlannings.guildId],
|
|
||||||
references: [guilds.id],
|
|
||||||
}),
|
|
||||||
messages: many(tpMessages),
|
messages: many(tpMessages),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const tpMessages = pgTable("tp_message", {
|
export const tpMessages = pgTable("tp_message", {
|
||||||
messageId: varchar("message_id", { length: 20 }).primaryKey(),
|
messageId: varchar("message_id", { length: 19 }).primaryKey(),
|
||||||
day: smallint("day").notNull(),
|
day: smallint("day").notNull(),
|
||||||
planId: integer("plan_id")
|
planId: varchar("plan_id", { length: 19 })
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => timePlannings.id, { onDelete: "cascade" }),
|
.references(() => timePlannings.guildId, { onDelete: "cascade" }),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const tpMessagesRelations = relations(tpMessages, ({ one }) => ({
|
export const tpMessagesRelations = relations(tpMessages, ({ one }) => ({
|
||||||
plan: one(timePlannings, {
|
timePlanning: one(timePlannings, {
|
||||||
fields: [tpMessages.planId],
|
fields: [tpMessages.messageId],
|
||||||
references: [timePlannings.id],
|
references: [timePlannings.channelId],
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { createHandler } from "@solidjs/start/entry";
|
import { createHandler, StartServer } from "@solidjs/start/server";
|
||||||
import { StartServer } from "@solidjs/start/server";
|
|
||||||
|
|
||||||
export default createHandler(() => (
|
export default createHandler(() => (
|
||||||
<StartServer
|
<StartServer
|
||||||
|
@ -8,7 +7,7 @@ export default createHandler(() => (
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/assets/favicon.ico" />
|
||||||
{assets}
|
{assets}
|
||||||
</head>
|
</head>
|
||||||
<body id="app">
|
<body id="app">
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { Title } from "@solidjs/meta";
|
import { Title } from "@solidjs/meta";
|
||||||
import { HttpStatusCode } from "@solidjs/start";
|
import { HttpStatusCode } from "@solidjs/start";
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/index.scss";
|
import "../styles/pages/index.scss";
|
||||||
|
|
||||||
export default function NotFound() {
|
export default function NotFound() {
|
||||||
return (
|
return (
|
||||||
<Layout site="index">
|
<>
|
||||||
<Title>Not Found</Title>
|
<Title>Not Found</Title>
|
||||||
<HttpStatusCode code={404} />
|
<HttpStatusCode code={404} />
|
||||||
<section class="index">
|
<section class="index">
|
||||||
|
@ -18,6 +17,6 @@ export default function NotFound() {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</Layout>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/about.scss";
|
import "../styles/pages/about.scss";
|
||||||
|
|
||||||
function about() {
|
function about() {
|
||||||
return (
|
return (
|
||||||
<Layout site="about">
|
<>
|
||||||
|
<div class="aboutdiv">
|
||||||
<h1>About</h1>
|
<h1>About</h1>
|
||||||
<section>
|
<section>
|
||||||
<h2>Why does this bot exist?</h2>
|
<h2>Why does this bot exist?</h2>
|
||||||
|
@ -12,19 +12,19 @@ function about() {
|
||||||
<a href="/assets/screenshots/oldplanningmsg.png" target="_blank">
|
<a href="/assets/screenshots/oldplanningmsg.png" target="_blank">
|
||||||
these planning messages
|
these planning messages
|
||||||
</a>{" "}
|
</a>{" "}
|
||||||
and I thought that this should be automated. Some time later the first
|
and I thought that this should be automated. Some time later the
|
||||||
version of li'l Judd was born. Today the bot has more features and
|
first version of li'l Judd was born. Today the bot has more features
|
||||||
keeps getting more of them! It is designed to actually improve the
|
and keeps getting more of them! It is designed to actually improve
|
||||||
Splatoon experience and not be the 10000th moderation and general
|
the Splatoon experience and not be the 10000th moderation and
|
||||||
utility bot with the same features as all bots.
|
general utility bot with the same features as all bots.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<h2>Who is behind this?</h2>
|
<h2>Who is behind this?</h2>
|
||||||
<p>
|
<p>
|
||||||
The bot is currently being developed by{" "}
|
The bot is currently being developed by{" "}
|
||||||
<a href="/contact">moonleay</a> (hey that's me!) with occasional
|
<a href="/contact">moonleay</a> (hey that's me!) with
|
||||||
help from his friends!
|
occasional help from his friends!
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
|
@ -36,17 +36,17 @@ function about() {
|
||||||
<a href="https://git.moonleay.net/DiscordBots/lilJudd">
|
<a href="https://git.moonleay.net/DiscordBots/lilJudd">
|
||||||
read the code
|
read the code
|
||||||
</a>
|
</a>
|
||||||
and if you still don't trust me, you can always host the bot yourself!
|
and if you still don't trust me, you can always host the bot
|
||||||
A guide on how to do that can be found in the README of the git
|
yourself! A guide on how to do that can be found in the README of
|
||||||
project.
|
the git project.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<h2>Where is my data stored?</h2>
|
<h2>Where is my data stored?</h2>
|
||||||
<p>
|
<p>
|
||||||
Your data is stored on a VPS from Contabo in Germany. The bot used to
|
Your data is stored on a VPS from Contabo in Germany. The bot used
|
||||||
be hosted on a server in my basement, but I moved it to a VPS, because
|
to be hosted on a server in my basement, but I moved it to a VPS,
|
||||||
my internet connection was not stable enough.
|
because my internet connection was not stable enough.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
|
@ -66,12 +66,13 @@ function about() {
|
||||||
<section>
|
<section>
|
||||||
<h2>Hey, there is this really cool idea I have! Can you add it?</h2>
|
<h2>Hey, there is this really cool idea I have! Can you add it?</h2>
|
||||||
<p>
|
<p>
|
||||||
Just message me! I can't promise anything, but I am always open to new
|
Just message me! I can't promise anything, but I am always open to
|
||||||
ideas and improvements! You can find ways to contact me{" "}
|
new ideas and improvements! You can find ways to contact me{" "}
|
||||||
<a href="/contact">here</a>.
|
<a href="/contact">here</a>.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</Layout>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/acknowledgements.scss";
|
import "../styles/pages/acknowledgements.scss";
|
||||||
|
|
||||||
function acknowledgements() {
|
function acknowledgements() {
|
||||||
return (
|
return (
|
||||||
<Layout site="acknowledgements">
|
<>
|
||||||
|
<div class="acknowledgements">
|
||||||
<h1>Acknowledgements</h1>
|
<h1>Acknowledgements</h1>
|
||||||
<section>
|
<section>
|
||||||
<table>
|
<table>
|
||||||
|
@ -142,7 +142,10 @@ function acknowledgements() {
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="https://github.com/JetBrains/Exposed" target="_blank">
|
<a
|
||||||
|
href="https://github.com/JetBrains/Exposed"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
repo
|
repo
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
@ -189,7 +192,8 @@ function acknowledgements() {
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
</Layout>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
57
src/routes/config.tsx
Normal file
57
src/routes/config.tsx
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import "../styles/pages/config.scss";
|
||||||
|
|
||||||
|
function config() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h3 class={"centered"}>Configure li'l Judd in</h3>
|
||||||
|
<div class={"config"}>
|
||||||
|
<div>
|
||||||
|
<div class={"horizontal centered"}>
|
||||||
|
<img class={"guildpfp"} src="https://cdn.discordapp.com/icons/1040502664506646548/bb5a51c4659cf47bdd942bb11e974da7.webp?size=240" alt="Server pfp" />
|
||||||
|
<h1>li'l Judds home base</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<article>
|
||||||
|
<h2>Timezone</h2>
|
||||||
|
<p>Set the timezone for your server.</p>
|
||||||
|
<label>
|
||||||
|
<select>
|
||||||
|
<option value="-1">UTC-1:00</option>
|
||||||
|
<option value="0">UTC+0:00</option>
|
||||||
|
<option value="1">UTC+1:00</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</article>
|
||||||
|
<section>
|
||||||
|
<div class={"centered"}>
|
||||||
|
<h2>Features</h2>
|
||||||
|
<p>Configure the features of the bot</p>
|
||||||
|
</div>
|
||||||
|
<article>
|
||||||
|
<div class={"horizontal"}>
|
||||||
|
<h3>Time Planning</h3>
|
||||||
|
<input type="checkbox" id="time planning" />
|
||||||
|
</div>
|
||||||
|
<label class={"horizontal"}>
|
||||||
|
<p class={"marg_right_5px"}>Target channel:</p>
|
||||||
|
<select>
|
||||||
|
<option value="id">Channel 1</option>
|
||||||
|
<option value="id">Channel 2</option>
|
||||||
|
<option value="id">Channel 3</option>
|
||||||
|
<option value="id">Channel 4</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<div class={"horizontal"}>
|
||||||
|
<h4>Enable pingable Roles</h4>
|
||||||
|
<input type="checkbox" id="pingableroles" />
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
<button>Apply</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default config;
|
|
@ -1,271 +0,0 @@
|
||||||
import { getSession } from "@auth/solid-start";
|
|
||||||
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 createClient from "openapi-fetch";
|
|
||||||
import { Index, createEffect, createResource, createSignal } from "solid-js";
|
|
||||||
import { createStore } from "solid-js/store";
|
|
||||||
import { getRequestEvent } from "solid-js/web";
|
|
||||||
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon";
|
|
||||||
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";
|
|
||||||
|
|
||||||
const guessTZ = () => Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
||||||
|
|
||||||
const initialValue = (params: ReturnType<typeof useParams>) => ({
|
|
||||||
success: null as boolean | null,
|
|
||||||
guild: {
|
|
||||||
id: params.guildId,
|
|
||||||
name: undefined as string | undefined,
|
|
||||||
icon: undefined as string | null | undefined,
|
|
||||||
},
|
|
||||||
tzNames: [guessTZ()],
|
|
||||||
});
|
|
||||||
|
|
||||||
const getPayload = async (
|
|
||||||
id: string,
|
|
||||||
): Promise<
|
|
||||||
| { success: false; message: string }
|
|
||||||
| (ReturnType<typeof initialValue> & { success: true })
|
|
||||||
> => {
|
|
||||||
"use server";
|
|
||||||
const event = getRequestEvent();
|
|
||||||
if (!event) return { success: false, message: "No request event!" };
|
|
||||||
|
|
||||||
const session = await getSession(event.request, authOptions);
|
|
||||||
if (!session?.user?.id)
|
|
||||||
return { success: false, message: "No user with id!" };
|
|
||||||
|
|
||||||
const { DISCORD_ACCESS_TOKEN } = (
|
|
||||||
await db
|
|
||||||
.selectDistinct({ DISCORD_ACCESS_TOKEN: accounts.access_token })
|
|
||||||
.from(accounts)
|
|
||||||
.where(eq(accounts.userId, session.user?.id))
|
|
||||||
.limit(1)
|
|
||||||
.execute()
|
|
||||||
)[0];
|
|
||||||
if (!DISCORD_ACCESS_TOKEN)
|
|
||||||
return { success: false, message: "No discord access token!" };
|
|
||||||
|
|
||||||
// const guilds = await fetch("https://discord.com/api/users/@me/guilds", {
|
|
||||||
// headers: { Authorization: `Bearer ${DISCORD_ACCESS_TOKEN}` },
|
|
||||||
// }).then((res) => res.json());
|
|
||||||
const { GET } = createClient<paths>({
|
|
||||||
baseUrl: "https://discord.com/api/v10",
|
|
||||||
});
|
|
||||||
const { data: guilds, error } = await GET("/users/@me/guilds", {
|
|
||||||
headers: { Authorization: `Bearer ${DISCORD_ACCESS_TOKEN}` },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.log(error);
|
|
||||||
return { success: false, message: "Error on discord api request!" };
|
|
||||||
}
|
|
||||||
|
|
||||||
const guild = guilds?.find((e) => e.id === id);
|
|
||||||
|
|
||||||
if (!guild)
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: "User is in no such guild with requested id!",
|
|
||||||
};
|
|
||||||
if (!(parseInt(guild.permissions) & (1 << 5)))
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message:
|
|
||||||
"User is no MANAGE_GUILD permissions on this guild with requested id!",
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
guild: {
|
|
||||||
id: guild.id,
|
|
||||||
name: guild.name,
|
|
||||||
icon: guild.icon,
|
|
||||||
},
|
|
||||||
// guild: guilds
|
|
||||||
// .filter((e: any) => e.permissions & (1 << 5))
|
|
||||||
// .map((e: any) => e.name),
|
|
||||||
tzNames: moment.tz.names(),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function config() {
|
|
||||||
const params = useParams();
|
|
||||||
const navigator = useNavigate();
|
|
||||||
let timezoneRef: HTMLInputElement;
|
|
||||||
let timePlanningRef: HTMLInputElement;
|
|
||||||
let pingableRolesRef: HTMLInputElement;
|
|
||||||
|
|
||||||
const [timezone, setTimezone] = createSignal(guessTZ());
|
|
||||||
const [payload] = createResource(params.guildId, async (id) => {
|
|
||||||
const payload = await getPayload(id);
|
|
||||||
|
|
||||||
if (!payload.success) {
|
|
||||||
console.log(payload.message, "No success");
|
|
||||||
navigator("/config", { replace: false });
|
|
||||||
return initialValue(params);
|
|
||||||
}
|
|
||||||
return payload;
|
|
||||||
});
|
|
||||||
const guild = () => payload()?.guild ?? initialValue(params).guild;
|
|
||||||
const tzNames = () => payload()?.tzNames ?? [];
|
|
||||||
const [config, setConfig] = createStore({
|
|
||||||
features: {
|
|
||||||
timePlanning: {
|
|
||||||
enabled: false,
|
|
||||||
pingableRoles: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
createEffect(() => console.log(payload()));
|
|
||||||
createEffect(() => console.log("timezone", timezone()));
|
|
||||||
createEffect(() =>
|
|
||||||
console.log("timePlanning.enabled", config.features.timePlanning.enabled),
|
|
||||||
);
|
|
||||||
createEffect(() =>
|
|
||||||
console.log(
|
|
||||||
"timePlanning.pingableRoles",
|
|
||||||
config.features.timePlanning.pingableRoles,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
createEffect(() => (timezoneRef.value = timezone()));
|
|
||||||
createEffect(
|
|
||||||
() => (timePlanningRef.checked = config.features.timePlanning.enabled),
|
|
||||||
);
|
|
||||||
createEffect(
|
|
||||||
() =>
|
|
||||||
(pingableRolesRef.checked = config.features.timePlanning.pingableRoles),
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout site="config">
|
|
||||||
<h3 class="text-center">Configure li'l Judd in</h3>
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<div class="flex-row centered">
|
|
||||||
<img
|
|
||||||
class="guildpfp"
|
|
||||||
src={
|
|
||||||
guild()?.icon
|
|
||||||
? `https://cdn.discordapp.com/icons/${guild()?.id}/${guild()
|
|
||||||
?.icon}.webp?size=240`
|
|
||||||
: "https://cdn.discordapp.com/icons/1040502664506646548/bb5a51c4659cf47bdd942bb11e974da7.webp?size=240"
|
|
||||||
}
|
|
||||||
alt="Server pfp"
|
|
||||||
/>
|
|
||||||
<h1>{guild()?.name ?? "li'l Judds home base"}</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h2>Guild</h2>
|
|
||||||
<p>General settings for this guild.</p>
|
|
||||||
<div class="flex-row">
|
|
||||||
<label for="timezone">Timezone for your server:</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
list="timezones"
|
|
||||||
id="timezone"
|
|
||||||
ref={timezoneRef!}
|
|
||||||
// disabled={!tzNames().find((e) => e === timezone())}
|
|
||||||
onInput={(e) => setTimezone(e.target.value)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<datalist id="timezones">
|
|
||||||
<Index each={tzNames()}>
|
|
||||||
{(zone) => <option value={zone()} />}
|
|
||||||
</Index>
|
|
||||||
</datalist>
|
|
||||||
|
|
||||||
<button
|
|
||||||
disabled={guessTZ() === timezone()}
|
|
||||||
title={"Detected: " + guessTZ()}
|
|
||||||
onClick={() => setTimezone(guessTZ())}
|
|
||||||
>
|
|
||||||
Auto-detect
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h2>Features</h2>
|
|
||||||
<p>Configure the features of the bot</p>
|
|
||||||
<label for="timePlanning" class="flex-row">
|
|
||||||
<p>Time Planning </p>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
icon={
|
|
||||||
config.features.timePlanning.enabled ? faToggleOn : faToggleOff
|
|
||||||
}
|
|
||||||
size="xl"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
hidden
|
|
||||||
type="checkbox"
|
|
||||||
id="timePlanning"
|
|
||||||
ref={timePlanningRef!}
|
|
||||||
onInput={(e) =>
|
|
||||||
setConfig("features", "timePlanning", "enabled", e.target.checked)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<div
|
|
||||||
class="sub"
|
|
||||||
classList={{ disabled: !config.features.timePlanning.enabled }}
|
|
||||||
>
|
|
||||||
<div class="flex-row">
|
|
||||||
<label>Target channel:</label>
|
|
||||||
<select value={timezone()}>
|
|
||||||
<optgroup label="--Select a Channel--">
|
|
||||||
<Index each={tzNames()}>
|
|
||||||
{(channel) => <option>{channel()}</option>}
|
|
||||||
</Index>
|
|
||||||
</optgroup>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="flex-row">
|
|
||||||
<label for="pingableRoles" class="flex-row">
|
|
||||||
<p>Enable pingable Roles:</p>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
icon={
|
|
||||||
config.features.timePlanning.pingableRoles
|
|
||||||
? faToggleOn
|
|
||||||
: faToggleOff
|
|
||||||
}
|
|
||||||
size="xl"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
hidden
|
|
||||||
type="checkbox"
|
|
||||||
id="pingableRoles"
|
|
||||||
ref={pingableRolesRef!}
|
|
||||||
onInput={(e) =>
|
|
||||||
setConfig(
|
|
||||||
"features",
|
|
||||||
"timePlanning",
|
|
||||||
"pingableRoles",
|
|
||||||
e.target.checked,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<button>Apply</button>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default config;
|
|
|
@ -1,124 +0,0 @@
|
||||||
import { getSession } from "@auth/solid-start";
|
|
||||||
import {
|
|
||||||
faBadgeCheck,
|
|
||||||
faCircleExclamation,
|
|
||||||
faPlus,
|
|
||||||
} 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 db from "~/drizzle";
|
|
||||||
import { accounts } from "~/drizzle/schema";
|
|
||||||
import { authOptions } from "~/server/auth";
|
|
||||||
import { paths } from "~/types/discord";
|
|
||||||
import "../../styles/pages/config.scss";
|
|
||||||
|
|
||||||
const initialValue = () => ({
|
|
||||||
success: null as boolean | null,
|
|
||||||
guilds: [] as {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
icon: string | null | undefined;
|
|
||||||
}[],
|
|
||||||
});
|
|
||||||
|
|
||||||
const getPayload = async (): Promise<
|
|
||||||
| { success: false; message: string }
|
|
||||||
| (ReturnType<typeof initialValue> & { success: true })
|
|
||||||
> => {
|
|
||||||
("use server");
|
|
||||||
const event = getRequestEvent();
|
|
||||||
if (!event) return { success: false, message: "No request event!" };
|
|
||||||
|
|
||||||
const session = await getSession(event.request, authOptions);
|
|
||||||
if (!session?.user?.id)
|
|
||||||
return { success: false, message: "No user with id!" };
|
|
||||||
|
|
||||||
const { DISCORD_ACCESS_TOKEN } = (
|
|
||||||
await db
|
|
||||||
.selectDistinct({ DISCORD_ACCESS_TOKEN: accounts.access_token })
|
|
||||||
.from(accounts)
|
|
||||||
.where(eq(accounts.userId, session.user?.id))
|
|
||||||
.limit(1)
|
|
||||||
.execute()
|
|
||||||
)[0];
|
|
||||||
if (!DISCORD_ACCESS_TOKEN)
|
|
||||||
return { success: false, message: "No discord access token!" };
|
|
||||||
|
|
||||||
const { GET } = createClient<paths>({
|
|
||||||
baseUrl: "https://discord.com/api/v10",
|
|
||||||
});
|
|
||||||
const { data: guilds, error } = await GET("/users/@me/guilds", {
|
|
||||||
headers: { Authorization: `Bearer ${DISCORD_ACCESS_TOKEN}` },
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("guilds", guilds);
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.log(error);
|
|
||||||
return { success: false, message: "Error on discord api request!" };
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
guilds:
|
|
||||||
guilds
|
|
||||||
?.filter((e) => parseInt(e.permissions) & (1 << 5))
|
|
||||||
.map(({ id, name, icon }) => ({ id, name, icon })) ?? [],
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
function index() {
|
|
||||||
const navigator = useNavigate();
|
|
||||||
|
|
||||||
const [payload] = createResource(async () => {
|
|
||||||
const payload = await getPayload();
|
|
||||||
|
|
||||||
if (!payload.success) {
|
|
||||||
console.log(payload.message, "No success");
|
|
||||||
navigator("/", { replace: false });
|
|
||||||
return initialValue();
|
|
||||||
}
|
|
||||||
console.log("success");
|
|
||||||
return payload;
|
|
||||||
});
|
|
||||||
|
|
||||||
const icons = [faPlus, faCircleExclamation, faBadgeCheck];
|
|
||||||
const colors = [undefined, "orange", "green"];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout site="config">
|
|
||||||
<h3 class="text-center">Configure li'l Judd in</h3>
|
|
||||||
<div>
|
|
||||||
<For each={payload()?.guilds ?? []}>
|
|
||||||
{(guild, i) => (
|
|
||||||
<a href={`/config/${guild.id}`} class="flex-row centered">
|
|
||||||
<img
|
|
||||||
class="guildpfp"
|
|
||||||
src={
|
|
||||||
guild.icon
|
|
||||||
? `https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.webp?size=240`
|
|
||||||
: "https://cdn.discordapp.com/icons/1040502664506646548/bb5a51c4659cf47bdd942bb11e974da7.webp?size=240"
|
|
||||||
}
|
|
||||||
alt="Server pfp"
|
|
||||||
/>
|
|
||||||
<h1>{guild.name}</h1>
|
|
||||||
<FontAwesomeIcon
|
|
||||||
// beat={i() % 3 === 1}
|
|
||||||
color={colors[i() % 3]}
|
|
||||||
icon={icons[i() % 3]}
|
|
||||||
size="xl"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default index;
|
|
|
@ -1,16 +1,19 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/contact.scss";
|
import "../styles/pages/contact.scss";
|
||||||
|
|
||||||
function contact() {
|
function contact() {
|
||||||
return (
|
return (
|
||||||
<Layout site="contact">
|
<>
|
||||||
|
<div class="contact">
|
||||||
<h1>Contact</h1>
|
<h1>Contact</h1>
|
||||||
<section>
|
<section class="contact">
|
||||||
<a href="mailto:contact@moonleay.net" target="_blank">
|
<a href="mailto:contact@moonleay.net" target="_blank">
|
||||||
<img src="/assets/icons/email.svg" alt="Email" />
|
<img src="/assets/icons/email.svg" alt="Email" />
|
||||||
contact@moonleay.net
|
contact@moonleay.net
|
||||||
</a>
|
</a>
|
||||||
<a href="https://discord.com/users/372703841151614976" target="_blank">
|
<a
|
||||||
|
href="https://discord.com/users/372703841151614976"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
<img src="/assets/icons/discord.svg" alt="Discord" />
|
<img src="/assets/icons/discord.svg" alt="Discord" />
|
||||||
@moonleay
|
@moonleay
|
||||||
</a>
|
</a>
|
||||||
|
@ -19,7 +22,8 @@ function contact() {
|
||||||
li'l Judd's home base
|
li'l Judd's home base
|
||||||
</a>
|
</a>
|
||||||
</section>
|
</section>
|
||||||
</Layout>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import ImageSection from "~/components/ImageSection";
|
import ImageSection from "~/components/ImageSection";
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/features.scss";
|
import "../styles/pages/features.scss";
|
||||||
|
|
||||||
function features() {
|
function features() {
|
||||||
return (
|
return (
|
||||||
<Layout site="features">
|
<>
|
||||||
<h1>Features</h1>
|
<div class="features">
|
||||||
|
<h1 class="title">Features</h1>
|
||||||
<div class="gridlayout">
|
<div class="gridlayout">
|
||||||
<ImageSection
|
<ImageSection
|
||||||
imgUrl="/assets/screenshots/timeplanner.png"
|
imgUrl="/assets/screenshots/timeplanner.png"
|
||||||
|
@ -44,7 +44,8 @@ function features() {
|
||||||
note="If you have a specific feature request, you can contact me on Discord: @moonleay or email: contact at moonleay dot net"
|
note="If you have a specific feature request, you can contact me on Discord: @moonleay or email: contact at moonleay dot net"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/how-do-i.scss";
|
import "../styles/pages/how-do-i.scss";
|
||||||
|
|
||||||
function howDoI() {
|
function howDoI() {
|
||||||
return (
|
return (
|
||||||
<Layout site="how-do-i">
|
<>
|
||||||
<h1>How do I...?</h1>
|
<h1 class="hdi-title">How do I...?</h1>
|
||||||
<section>
|
<section class="hdi-section">
|
||||||
<h2>.. enable / disable certain features?</h2>
|
<h2>.. enable / disable certain features?</h2>
|
||||||
<p>
|
<p>
|
||||||
Features can be enabled and disables using the <code>/feature</code>
|
Features can be enabled and disables using the <code>/feature</code>
|
||||||
|
@ -27,7 +26,7 @@ function howDoI() {
|
||||||
{/* <p><code>/feature feature:Time Planning Feature set:Enable channel:#ich-kann-heute</code></p> */}
|
{/* <p><code>/feature feature:Time Planning Feature set:Enable channel:#ich-kann-heute</code></p> */}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section class="hdi-section">
|
||||||
<h2>.. create a match?</h2>
|
<h2>.. create a match?</h2>
|
||||||
<p>
|
<p>
|
||||||
You can create a match time using the <code>/match</code> command.
|
You can create a match time using the <code>/match</code> command.
|
||||||
|
@ -48,14 +47,14 @@ function howDoI() {
|
||||||
{/* <p><code>/match match:Ladder Match timestamp:24.12.2069 04:20 opponent:Forbidden</code></p> */}
|
{/* <p><code>/match match:Ladder Match timestamp:24.12.2069 04:20 opponent:Forbidden</code></p> */}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="note">
|
<section class="hdi-footernotesection">
|
||||||
<p>
|
<p>
|
||||||
Is something missing here?
|
Is something missing here?
|
||||||
<br />
|
<br />
|
||||||
Please <a href="/contact">contact me</a>!
|
Please <a href="/contact">contact me</a>!
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</Layout>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/imprint.scss";
|
import "../styles/pages/imprint.scss";
|
||||||
|
|
||||||
function imprint() {
|
function imprint() {
|
||||||
return (
|
return (
|
||||||
<Layout site="imprint">
|
<>
|
||||||
<section>
|
<section class="imprint">
|
||||||
<h1>Imprint</h1>
|
<h1>Imprint</h1>
|
||||||
<section>
|
<section>
|
||||||
<a href="/contact">
|
<a href="/contact">
|
||||||
|
@ -55,7 +54,7 @@ function imprint() {
|
||||||
</h5>
|
</h5>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</Layout>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/index.scss";
|
import "../styles/pages/index.scss";
|
||||||
|
|
||||||
function index() {
|
function index() {
|
||||||
return (
|
return (
|
||||||
<Layout site="index">
|
<>
|
||||||
<section>
|
<section class="index">
|
||||||
<h1>li'l Judd</h1>
|
<h1>li'l Judd</h1>
|
||||||
<h5>The competetive Splatoon Bot</h5>
|
<h5>The competetive Splatoon Bot</h5>
|
||||||
<div>
|
<div>
|
||||||
|
@ -14,7 +13,7 @@ function index() {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</Layout>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/privacy-policy.scss";
|
import "../styles/pages/privacy-policy.scss";
|
||||||
|
|
||||||
function privacyPolicy() {
|
function privacyPolicy() {
|
||||||
return (
|
return (
|
||||||
<Layout site="privacyPolicy">
|
<>
|
||||||
|
<div class="privacyPolicy">
|
||||||
<div>
|
<div>
|
||||||
<h1>Privacy Policy for li'l Judd</h1>
|
<h1>Privacy Policy for li'l Judd</h1>
|
||||||
<h4>Last updated: 2023-12-05</h4>
|
<h4>Last updated: 2023-12-05</h4>
|
||||||
|
@ -57,8 +57,8 @@ function privacyPolicy() {
|
||||||
</ul>
|
</ul>
|
||||||
<h3>3.2 Usage Data</h3>
|
<h3>3.2 Usage Data</h3>
|
||||||
<p>
|
<p>
|
||||||
We may collect information on how you interact with our bot, including
|
We may collect information on how you interact with our bot,
|
||||||
but not limited to:
|
including but not limited to:
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
|
@ -96,8 +96,8 @@ function privacyPolicy() {
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<p>
|
<p>
|
||||||
- Consent: You have given your consent for the processing of your
|
- Consent: You have given your consent for the processing of
|
||||||
personal data for one or more specific purposes.
|
your personal data for one or more specific purposes.
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
@ -111,8 +111,9 @@ function privacyPolicy() {
|
||||||
<section>
|
<section>
|
||||||
<h2>6. Data Sharing</h2>
|
<h2>6. Data Sharing</h2>
|
||||||
<p>
|
<p>
|
||||||
We do not sell, trade, or otherwise transfer your personal information
|
We do not sell, trade, or otherwise transfer your personal
|
||||||
to third parties. However, we may share your information with:
|
information to third parties. However, we may share your information
|
||||||
|
with:
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
|
@ -150,8 +151,8 @@ function privacyPolicy() {
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p>
|
<p>
|
||||||
- Right to erasure: You can request the deletion of your personal
|
- Right to erasure: You can request the deletion of your
|
||||||
data.
|
personal data.
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -159,8 +160,8 @@ function privacyPolicy() {
|
||||||
<section>
|
<section>
|
||||||
<h2>9. Changes to this Privacy Policy</h2>
|
<h2>9. Changes to this Privacy Policy</h2>
|
||||||
<p>
|
<p>
|
||||||
We may update this Privacy Policy to reflect changes in our practices.
|
We may update this Privacy Policy to reflect changes in our
|
||||||
The updated version will be posted on
|
practices. The updated version will be posted on
|
||||||
https://liljudd.ink/privacy-policy.
|
https://liljudd.ink/privacy-policy.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
@ -171,7 +172,8 @@ function privacyPolicy() {
|
||||||
please contact us at contact@moonleay.net.
|
please contact us at contact@moonleay.net.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</Layout>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/stack.scss";
|
import "../styles/pages/stack.scss";
|
||||||
|
|
||||||
function stack() {
|
function stack() {
|
||||||
return (
|
return (
|
||||||
<Layout site="stack">
|
<>
|
||||||
<h1>The Stack</h1>
|
<h1 class="stack-title">The Stack</h1>
|
||||||
<section>
|
<section class="stack-section">
|
||||||
<img src="/assets/logos/kotlin.svg" alt="Kotlin 'K' logo" />
|
<img src="/assets/logos/kotlin.svg" alt="Kotlin 'K' logo" />
|
||||||
<div class="stackgrid_3 stackitm">
|
<div class="stackgrid_3 stackitm">
|
||||||
<h1>The Kotlin programming language</h1>
|
<h1>The Kotlin programming language</h1>
|
||||||
|
@ -15,14 +14,14 @@ function stack() {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section class="stack-section">
|
||||||
<img src="/assets/logos/kord.png" alt="The Kord logo" />
|
<img src="/assets/logos/kord.png" alt="The Kord logo" />
|
||||||
<div class="stackgrid_3 stackitm">
|
<div class="stackgrid_3 stackitm">
|
||||||
<h1>The Kord library</h1>
|
<h1>The Kord library</h1>
|
||||||
<p>A Kotlin library for creating Discord bots. Pretty bare bones.</p>
|
<p>A Kotlin library for creating Discord bots. Pretty bare bones.</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section class="stack-section">
|
||||||
<img
|
<img
|
||||||
src="/assets/logos/kordextensions.png"
|
src="/assets/logos/kordextensions.png"
|
||||||
alt="The Kord-Extensions logo"
|
alt="The Kord-Extensions logo"
|
||||||
|
@ -32,7 +31,7 @@ function stack() {
|
||||||
<p>A Kotlin library to improve the Kord experience.</p>
|
<p>A Kotlin library to improve the Kord experience.</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section class="stack-section">
|
||||||
<img src="/assets/logos/pgelephant.png" alt="The PostgreSQL elephant" />
|
<img src="/assets/logos/pgelephant.png" alt="The PostgreSQL elephant" />
|
||||||
<div class="stackgrid_3 stackitm">
|
<div class="stackgrid_3 stackitm">
|
||||||
<h1>The PostgreSQL database</h1>
|
<h1>The PostgreSQL database</h1>
|
||||||
|
@ -48,7 +47,7 @@ function stack() {
|
||||||
<a href="/acknowledgements">Acknowledgements</a>.
|
<a href="/acknowledgements">Acknowledgements</a>.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</Layout>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import Layout from "~/components/Layout";
|
|
||||||
import "../styles/pages/terms-of-service.scss";
|
import "../styles/pages/terms-of-service.scss";
|
||||||
|
|
||||||
function termsOfService() {
|
function termsOfService() {
|
||||||
return (
|
return (
|
||||||
<Layout site="termsOfService">
|
<>
|
||||||
|
<div class="termsOfService">
|
||||||
<h1>Terms of Service</h1>
|
<h1>Terms of Service</h1>
|
||||||
<div>
|
<div>
|
||||||
<h2>Usage Agreement</h2>
|
<h2>Usage Agreement</h2>
|
||||||
<p>
|
<p>
|
||||||
By inviting the bot and using its features (commands, planning system)
|
By inviting the bot and using its features (commands, planning
|
||||||
are you agreeing to the below mentioned Terms and Privacy Policy
|
system) are you agreeing to the below mentioned Terms and Privacy
|
||||||
(Policy) of the bot.
|
Policy (Policy) of the bot.
|
||||||
<br />
|
<br />
|
||||||
You acknowledge that you have the privilege to use the bot freely on
|
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
|
any Discord Server (Server) you share with it, that you can invite
|
||||||
to any Server that you have "Manage Server" rights for and that this
|
it to any Server that you have "Manage Server" rights for and that
|
||||||
privilege might get revoked for you, if you're subject of breaking the
|
this privilege might get revoked for you, if you're subject of
|
||||||
terms and/or policy of this bot, or the{" "}
|
breaking the terms and/or policy of this bot, or the{" "}
|
||||||
<a href="https://discord.com/terms" target="_blank">
|
<a href="https://discord.com/terms" target="_blank">
|
||||||
Terms of Service
|
Terms of Service
|
||||||
</a>
|
</a>
|
||||||
|
@ -33,11 +33,11 @@ function termsOfService() {
|
||||||
Discord Inc
|
Discord Inc
|
||||||
</a>
|
</a>
|
||||||
.<br />
|
.<br />
|
||||||
Through Inviting the bot may it collect specific data as described in
|
Through Inviting the bot may it collect specific data as described
|
||||||
its Policy.
|
in its Policy.
|
||||||
<br />
|
<br />
|
||||||
The intended usage of this data is for core functionalities of the bot
|
The intended usage of this data is for core functionalities of the
|
||||||
such as command handling, guild-specific settings and the
|
bot such as command handling, guild-specific settings and the
|
||||||
time-planning system.
|
time-planning system.
|
||||||
<br />
|
<br />
|
||||||
</p>
|
</p>
|
||||||
|
@ -45,11 +45,11 @@ function termsOfService() {
|
||||||
<div>
|
<div>
|
||||||
<h2>Intended Age</h2>
|
<h2>Intended Age</h2>
|
||||||
<p>
|
<p>
|
||||||
The bot may not be used by individuals under the minimal age described
|
The bot may not be used by individuals under the minimal age
|
||||||
in Discord's Terms of Service.
|
described in Discord's Terms of Service.
|
||||||
<br />
|
<br />
|
||||||
Doing so will be seen as a violation of these terms and will result in
|
Doing so will be seen as a violation of these terms and will result
|
||||||
a removal of the bot from any servers you own.
|
in a removal of the bot from any servers you own.
|
||||||
<br />
|
<br />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -60,7 +60,8 @@ function termsOfService() {
|
||||||
<br />
|
<br />
|
||||||
Any direct connection to Discord or any of its Trademark objects is
|
Any direct connection to Discord or any of its Trademark objects is
|
||||||
purely coincidental. We do not claim to have the copyright ownership
|
purely coincidental. We do not claim to have the copyright ownership
|
||||||
of any of Discord's assets, trademarks or other intellectual property.
|
of any of Discord's assets, trademarks or other intellectual
|
||||||
|
property.
|
||||||
<br />
|
<br />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -70,25 +71,26 @@ function termsOfService() {
|
||||||
The owner of the bot may not be made liable for individuals breaking
|
The owner of the bot may not be made liable for individuals breaking
|
||||||
these Terms at any given time.
|
these Terms at any given time.
|
||||||
<br />
|
<br />
|
||||||
He has faith in the end users being truthfull about their information
|
He has faith in the end users being truthfull about their
|
||||||
and not misusing this bot or the services of Discord Inc in a
|
information and not misusing this bot or the services of Discord Inc
|
||||||
malicious way.
|
in a malicious way.
|
||||||
<br />
|
<br />
|
||||||
We reserve the right to update these terms at our own discretion,
|
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
|
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
|
you're not agreeing with the new changes. You may opt out by
|
||||||
the bot from any Server you have the rights for.
|
Removing the bot from any Server you have the rights for.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2>Contact</h2>
|
<h2>Contact</h2>
|
||||||
<p>
|
<p>
|
||||||
People may get in contact through e-mail at contact@moonleay.net, or
|
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
|
through the official Support Discord of the Bot. Other ways of
|
||||||
may be provided but aren't guaranteed.
|
support may be provided but aren't guaranteed.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,23 +7,15 @@ export const authOptions: SolidAuthConfig = {
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
...Discord({
|
...Discord({
|
||||||
clientId: import.meta.env.VITE_DISCORD_CLIENT_ID,
|
clientId: process.env.DISCORD_CLIENT_ID,
|
||||||
clientSecret: import.meta.env.VITE_DISCORD_CLIENT_SECRET,
|
clientSecret: process.env.DISCORD_CLIENT_SECRET,
|
||||||
}),
|
}),
|
||||||
authorization:
|
authorization:
|
||||||
"https://discord.com/api/oauth2/authorize?scope=identify+email+guilds+guilds.members.read",
|
"https://discord.com/api/oauth2/authorize?scope=identify+email+guilds+guilds.members.read",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
adapter: DrizzleAdapter(db),
|
adapter: DrizzleAdapter(db),
|
||||||
secret: import.meta.env.VITE_AUTH_SECRET,
|
secret: process.env.AUTH_SECRET,
|
||||||
callbacks: {
|
|
||||||
session: ({ session, user }) => {
|
|
||||||
if (session?.user) {
|
|
||||||
session.user.id = user.id;
|
|
||||||
}
|
|
||||||
return session;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
pages: {
|
pages: {
|
||||||
// signIn: "/signin",
|
// signIn: "/signin",
|
||||||
// signOut: "/signout",
|
// signOut: "/signout",
|
||||||
|
@ -31,7 +23,4 @@ export const authOptions: SolidAuthConfig = {
|
||||||
// verifyRequest: '/auth/verify-request', // (used for check email message)
|
// verifyRequest: '/auth/verify-request', // (used for check email message)
|
||||||
// newUser: '/auth/new-user' // New users will be directed here on first sign in (leave the property out if not of interest)
|
// newUser: '/auth/new-user' // New users will be directed here on first sign in (leave the property out if not of interest)
|
||||||
},
|
},
|
||||||
redirectProxyUrl: import.meta.env.DEV
|
|
||||||
? import.meta.env.VITE_AUTH_REDIRECT_PROXY_URL
|
|
||||||
: undefined,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -53,24 +53,3 @@ a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex-row {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
|
|
||||||
&.centered {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.thick {
|
|
||||||
align-items: initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.responsive {
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,73 +5,46 @@ nav {
|
||||||
backdrop-filter: blur(5px);
|
backdrop-filter: blur(5px);
|
||||||
position: sticky;
|
position: sticky;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
ul .navElem a {
|
ul {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.navElem {
|
||||||
|
margin: 0.5rem 1rem;
|
||||||
|
transition: 0.5s;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 0 1rem;
|
|
||||||
vertical-align: middle;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: rgb(96 59 255) !important;
|
color: rgb(96 59 255) !important;
|
||||||
|
|
||||||
.swap {
|
|
||||||
svg path {
|
|
||||||
transition: color 0.5s 0.5s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.primary {
|
.textBx {
|
||||||
opacity: 0;
|
display: flex;
|
||||||
}
|
align-items: center;
|
||||||
|
|
||||||
.secondary {
|
#logo {
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
img,
|
|
||||||
.swap,
|
|
||||||
.swap svg {
|
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
max-width: initial;
|
max-width: initial;
|
||||||
max-height: initial;
|
max-height: initial;
|
||||||
}
|
margin: 0.5rem;
|
||||||
|
|
||||||
.swap {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
> * {
|
|
||||||
transition: opacity 0.5s;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.secondary {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
span,
|
|
||||||
> svg path {
|
|
||||||
transition: color 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lower {
|
|
||||||
margin-top: 2px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
height: 72px;
|
flex-direction: row;
|
||||||
|
padding: 0 2rem;
|
||||||
|
|
||||||
|
.navElem:last-child {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.about {
|
.aboutdiv {
|
||||||
max-width: 1100px;
|
max-width: 1100px;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -1,34 +1,38 @@
|
||||||
.config {
|
|
||||||
.text-center {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.guildpfp {
|
.guildpfp {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
.horizontal {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
h1 {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
p, h3, h4 {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.marg_right_5px {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
section,
|
.centered {
|
||||||
a {
|
text-align: center;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.config {
|
||||||
|
article {
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
max-width: 1100px;
|
max-width: 1100px;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
|
||||||
|
|
||||||
.sub {
|
|
||||||
margin-left: 10px;
|
|
||||||
|
|
||||||
&.disabled {
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
}
|
}
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
section {
|
.contact {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
h1 {
|
.title {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 1.2rem;
|
margin-bottom: 1.2rem;
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
.how-do-i {
|
.hdi-title {
|
||||||
h1 {
|
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 1.2rem;
|
margin-bottom: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
section {
|
.hdi-section {
|
||||||
max-width: 1100px;
|
max-width: 1100px;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -42,7 +41,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.note {
|
.hdi-footernotesection {
|
||||||
max-width: 1100px;
|
max-width: 1100px;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -63,4 +62,3 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
.stack {
|
.stack-title {
|
||||||
h1 {
|
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 1.2rem;
|
margin-bottom: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
section {
|
.stack-section {
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
|
@ -36,7 +35,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.note {
|
.stack-note {
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
|
@ -60,4 +59,3 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
15
src/types/authjs.d.ts
vendored
15
src/types/authjs.d.ts
vendored
|
@ -1,15 +0,0 @@
|
||||||
import { DefaultSession as DSession } from "@auth/core/types"
|
|
||||||
|
|
||||||
declare module "@auth/core/types" {
|
|
||||||
/**
|
|
||||||
* Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
|
|
||||||
*/
|
|
||||||
interface Session extends DSession {
|
|
||||||
user?: {
|
|
||||||
id: string
|
|
||||||
name?: string | null
|
|
||||||
email?: string | null
|
|
||||||
image?: string | null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
7751
src/types/discord.d.ts
vendored
7751
src/types/discord.d.ts
vendored
File diff suppressed because it is too large
Load diff
16
src/types/env.d.ts
vendored
16
src/types/env.d.ts
vendored
|
@ -1,16 +0,0 @@
|
||||||
/// <reference types="vinxi/client" />
|
|
||||||
|
|
||||||
interface ImportMetaEnv {
|
|
||||||
readonly VITE_DISCORD_CLIENT: string;
|
|
||||||
readonly VITE_DISCORD_CLIENT_SECRET: string;
|
|
||||||
readonly VITE_DISCORD_BOT_TOKEN: string;
|
|
||||||
|
|
||||||
readonly VITE_AUTH_SECRET: string;
|
|
||||||
readonly VITE_AUTH_REDIRECT_PROXY_URL: string | undefined;
|
|
||||||
|
|
||||||
readonly VITE_DATABASE_URL: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ImportMeta {
|
|
||||||
readonly env: ImportMetaEnv;
|
|
||||||
}
|
|
196
src/types/liljudd.d.ts
vendored
196
src/types/liljudd.d.ts
vendored
|
@ -1,196 +0,0 @@
|
||||||
/**
|
|
||||||
* This file was auto-generated by openapi-typescript.
|
|
||||||
* Do not make direct changes to the file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
export interface paths {
|
|
||||||
"/api/config/{guildId}": {
|
|
||||||
/**
|
|
||||||
* Find guild config by ID
|
|
||||||
* @description Returns a single guild config
|
|
||||||
*/
|
|
||||||
get: operations["getGuildById"];
|
|
||||||
/**
|
|
||||||
* Deletes a guild config by ID
|
|
||||||
* @description Delete a guild's config
|
|
||||||
*/
|
|
||||||
delete: operations["deleteGuildById"];
|
|
||||||
};
|
|
||||||
"/api/tp_messages/{guildId}": {
|
|
||||||
/**
|
|
||||||
* Find guild by ID for it's tp_messages
|
|
||||||
* @description Returns tp_messages for a guild
|
|
||||||
*/
|
|
||||||
get: operations["getTp_messagesOfGuildById"];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export type webhooks = Record<string, never>;
|
|
||||||
|
|
||||||
export interface components {
|
|
||||||
schemas: {
|
|
||||||
guildConfig: {
|
|
||||||
/**
|
|
||||||
* Format: varchar(19)
|
|
||||||
* @example 1234567890123456789
|
|
||||||
*/
|
|
||||||
guildID?: string;
|
|
||||||
features?: {
|
|
||||||
time_planning?: {
|
|
||||||
/**
|
|
||||||
* Format: varchar(19)
|
|
||||||
* @example 1234567890123456789
|
|
||||||
*/
|
|
||||||
channelID?: string;
|
|
||||||
/** @example 0 0 1 * * * 60o 1w */
|
|
||||||
cron?: string;
|
|
||||||
/**
|
|
||||||
* Format: varchar(19)
|
|
||||||
* @example 1234567890123456789
|
|
||||||
*/
|
|
||||||
isAvailableRoleId?: string;
|
|
||||||
/**
|
|
||||||
* Format: varchar(19)
|
|
||||||
* @example 1234567890123456789
|
|
||||||
*/
|
|
||||||
wantsToBeNotifieRoledId?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
matches?: components["schemas"]["match"][];
|
|
||||||
};
|
|
||||||
match: {
|
|
||||||
/**
|
|
||||||
* Format: varchar(19)
|
|
||||||
* @example 1234567890123456789
|
|
||||||
*/
|
|
||||||
channelID?: string;
|
|
||||||
/**
|
|
||||||
* Format: varchar(50)
|
|
||||||
* @example Scrim
|
|
||||||
*/
|
|
||||||
matchType?: string;
|
|
||||||
/**
|
|
||||||
* Format: varchar(19)
|
|
||||||
* @example 1234567890123456789
|
|
||||||
*/
|
|
||||||
createrId?: string;
|
|
||||||
/**
|
|
||||||
* Format: varchar(19)
|
|
||||||
* @example 1234567890123456789
|
|
||||||
*/
|
|
||||||
roleId?: string;
|
|
||||||
/**
|
|
||||||
* Format: varchar(100)
|
|
||||||
* @example ?
|
|
||||||
*/
|
|
||||||
opponentName?: string;
|
|
||||||
/**
|
|
||||||
* Format: varchar(19)
|
|
||||||
* @example 1234567890123456789
|
|
||||||
*/
|
|
||||||
messsageId?: string;
|
|
||||||
/** @example 0 0 1 5 2 2023 60o */
|
|
||||||
cron?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
responses: never;
|
|
||||||
parameters: never;
|
|
||||||
requestBodies: never;
|
|
||||||
headers: never;
|
|
||||||
pathItems: never;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type $defs = Record<string, never>;
|
|
||||||
|
|
||||||
export type external = Record<string, never>;
|
|
||||||
|
|
||||||
export interface operations {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find guild config by ID
|
|
||||||
* @description Returns a single guild config
|
|
||||||
*/
|
|
||||||
getGuildById: {
|
|
||||||
parameters: {
|
|
||||||
path: {
|
|
||||||
/** @description ID of guild config to return */
|
|
||||||
guildId: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
responses: {
|
|
||||||
/** @description successful operation */
|
|
||||||
200: {
|
|
||||||
content: {
|
|
||||||
"application/json": components["schemas"]["guildConfig"];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
/** @description Invalid ID supplied */
|
|
||||||
400: {
|
|
||||||
content: never;
|
|
||||||
};
|
|
||||||
/** @description Guild not found */
|
|
||||||
404: {
|
|
||||||
content: never;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Deletes a guild config by ID
|
|
||||||
* @description Delete a guild's config
|
|
||||||
*/
|
|
||||||
deleteGuildById: {
|
|
||||||
parameters: {
|
|
||||||
path: {
|
|
||||||
/** @description ID of guild config to delete */
|
|
||||||
guildId: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
responses: {
|
|
||||||
/** @description successful operation */
|
|
||||||
204: {
|
|
||||||
content: never;
|
|
||||||
};
|
|
||||||
/** @description Invalid ID supplied */
|
|
||||||
400: {
|
|
||||||
content: never;
|
|
||||||
};
|
|
||||||
/** @description Guild not found */
|
|
||||||
404: {
|
|
||||||
content: never;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Find guild by ID for it's tp_messages
|
|
||||||
* @description Returns tp_messages for a guild
|
|
||||||
*/
|
|
||||||
getTp_messagesOfGuildById: {
|
|
||||||
parameters: {
|
|
||||||
path: {
|
|
||||||
/** @description ID of guild's tp_messages to return */
|
|
||||||
guildId: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
responses: {
|
|
||||||
/** @description successful operation */
|
|
||||||
200: {
|
|
||||||
content: {
|
|
||||||
"application/json": components["schemas"]["guildConfig"];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
/** @description Time planning not enabled for this guild */
|
|
||||||
204: {
|
|
||||||
content: never;
|
|
||||||
};
|
|
||||||
/** @description Invalid ID supplied */
|
|
||||||
400: {
|
|
||||||
content: never;
|
|
||||||
};
|
|
||||||
/** @description Guild not found */
|
|
||||||
404: {
|
|
||||||
content: never;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
Loading…
Reference in a new issue