style: login and config working
This commit is contained in:
parent
a657906f4f
commit
55b81fac91
28 changed files with 2322 additions and 3469 deletions
|
@ -13,10 +13,18 @@
|
||||||
"@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",
|
||||||
"drizzle-orm": "^0.29.2",
|
"drizzle-orm": "^0.29.2",
|
||||||
|
"moment-timezone": "^0.5.44",
|
||||||
"postgres": "^3.4.3",
|
"postgres": "^3.4.3",
|
||||||
"solid-js": "^1.8.11",
|
"solid-js": "^1.8.11",
|
||||||
"vinxi": "^0.1.2"
|
"vinxi": "^0.1.2"
|
||||||
|
|
3451
pnpm-lock.yaml
3451
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -1,12 +1,10 @@
|
||||||
// @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 Footer from "./components/Footer";
|
import "./styles/global.scss";
|
||||||
import NavBar from "./components/NavBar";
|
|
||||||
import "./styles/GlobalLayout.css";
|
|
||||||
import "./styles/Layout.scss";
|
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
|
@ -18,9 +16,8 @@ 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>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
151
src/components/FontAwesomeIcon.tsx
Normal file
151
src/components/FontAwesomeIcon.tsx
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
18
src/components/Layout.tsx
Normal file
18
src/components/Layout.tsx
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
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,35 +1,53 @@
|
||||||
|
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>
|
<nav class="flex-row responsive">
|
||||||
<ul>
|
<ul class="flex-row responsive thick">
|
||||||
<li class="navElem">
|
<Li href="/" name="li'l Judd">
|
||||||
<a class="textBx" href="/">
|
<img src="/assets/logox256.png" alt="The Bots Logo" />
|
||||||
<img id="logo" src="/assets/logox256.png" alt="The Bots Logo" />
|
</Li>
|
||||||
li'l Judd
|
<Li href="/features" name="Features" />
|
||||||
</a>
|
<Li href="/how-do-i" name="How do I...?" />
|
||||||
</li>
|
<Li href="/stack" name="The Stack" />
|
||||||
<li class="navElem">
|
<Li href="/about" name="About" />
|
||||||
<a href="/features">Features</a>
|
</ul>
|
||||||
</li>
|
<ul class="flex-row responsive thick">
|
||||||
<li class="navElem">
|
<Li
|
||||||
<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"
|
||||||
target="_blank"
|
name="Invite to your server"
|
||||||
>
|
>
|
||||||
Invite to your server
|
<FontAwesomeIcon class="lower" icon={faCirclePlus} size="xl" />
|
||||||
</a>
|
</Li>
|
||||||
</li>
|
<Suspense>
|
||||||
|
<NavUser />
|
||||||
|
</Suspense>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
|
|
87
src/components/NavUser.tsx
Normal file
87
src/components/NavUser.tsx
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
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,11 @@
|
||||||
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">
|
||||||
|
@ -17,6 +18,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
|
and I thought that this should be automated. Some time later the first
|
||||||
first version of li'l Judd was born. Today the bot has more features
|
version of li'l Judd was born. Today the bot has more features and
|
||||||
and keeps getting more of them! It is designed to actually improve
|
keeps getting more of them! It is designed to actually improve the
|
||||||
the Splatoon experience and not be the 10000th moderation and
|
Splatoon experience and not be the 10000th moderation and general
|
||||||
general utility bot with the same features as all bots.
|
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
|
<a href="/contact">moonleay</a> (hey that's me!) with occasional
|
||||||
occasional help from his friends!
|
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
|
and if you still don't trust me, you can always host the bot yourself!
|
||||||
yourself! A guide on how to do that can be found in the README of
|
A guide on how to do that can be found in the README of the git
|
||||||
the git project.
|
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
|
Your data is stored on a VPS from Contabo in Germany. The bot used to
|
||||||
to be hosted on a server in my basement, but I moved it to a VPS,
|
be hosted on a server in my basement, but I moved it to a VPS, because
|
||||||
because my internet connection was not stable enough.
|
my internet connection was not stable enough.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
|
@ -66,13 +66,12 @@ 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
|
Just message me! I can't promise anything, but I am always open to new
|
||||||
new ideas and improvements! You can find ways to contact me{" "}
|
ideas and improvements! You can find ways to contact me{" "}
|
||||||
<a href="/contact">here</a>.
|
<a href="/contact">here</a>.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</Layout>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,10 +142,7 @@ function acknowledgements() {
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a
|
<a href="https://github.com/JetBrains/Exposed" target="_blank">
|
||||||
href="https://github.com/JetBrains/Exposed"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
repo
|
repo
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
@ -192,8 +189,7 @@ function acknowledgements() {
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</Layout>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,60 +1,270 @@
|
||||||
import "../styles/pages/config.scss";
|
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() {
|
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 (
|
return (
|
||||||
|
<Layout site="config">
|
||||||
|
<h3 class="text-center">Configure li'l Judd in</h3>
|
||||||
<div>
|
<div>
|
||||||
<h3 class={"centered"}>Configure li'l Judd in</h3>
|
|
||||||
<div class={"config"}>
|
|
||||||
<div>
|
<div>
|
||||||
<div class={"horizontal centered"}>
|
<div class="flex-row centered">
|
||||||
<img
|
<img
|
||||||
class={"guildpfp"}
|
class="guildpfp"
|
||||||
src="https://cdn.discordapp.com/icons/1040502664506646548/bb5a51c4659cf47bdd942bb11e974da7.webp?size=240"
|
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"
|
alt="Server pfp"
|
||||||
/>
|
/>
|
||||||
<h1>li'l Judds home base</h1>
|
<h1>{guild()?.name ?? "li'l Judds home base"}</h1>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
<section>
|
||||||
<div class={"centered"}>
|
<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>
|
<h2>Features</h2>
|
||||||
<p>Configure the features of the bot</p>
|
<p>Configure the features of the bot</p>
|
||||||
</div>
|
<label for="timePlanning" class="flex-row">
|
||||||
<article>
|
<p>Time Planning </p>
|
||||||
<div class={"horizontal"}>
|
<FontAwesomeIcon
|
||||||
<h3>Time Planning</h3>
|
icon={
|
||||||
<input type="checkbox" id="time planning" />
|
config.features.timePlanning.enabled ? faToggleOn : faToggleOff
|
||||||
</div>
|
}
|
||||||
<label class={"horizontal"}>
|
size="xl"
|
||||||
<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>
|
</label>
|
||||||
<div class={"horizontal"}>
|
<input
|
||||||
<h4>Enable pingable Roles</h4>
|
hidden
|
||||||
<input type="checkbox" id="pingableroles" />
|
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>
|
</div>
|
||||||
</article>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
<button>Apply</button>
|
<button>Apply</button>
|
||||||
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Layout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
124
src/routes/config/index.tsx
Normal file
124
src/routes/config/index.tsx
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
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,19 +1,16 @@
|
||||||
|
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 class="contact">
|
<section>
|
||||||
<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
|
<a href="https://discord.com/users/372703841151614976" target="_blank">
|
||||||
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>
|
||||||
|
@ -22,8 +19,7 @@ function contact() {
|
||||||
li'l Judd's home base
|
li'l Judd's home base
|
||||||
</a>
|
</a>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</Layout>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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">
|
||||||
<div class="features">
|
<h1>Features</h1>
|
||||||
<h1 class="title">Features</h1>
|
|
||||||
<div class="gridlayout">
|
<div class="gridlayout">
|
||||||
<ImageSection
|
<ImageSection
|
||||||
imgUrl="/assets/screenshots/timeplanner.png"
|
imgUrl="/assets/screenshots/timeplanner.png"
|
||||||
|
@ -44,8 +44,7 @@ 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>
|
||||||
</div>
|
</Layout>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
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 class="hdi-title">How do I...?</h1>
|
<h1>How do I...?</h1>
|
||||||
<section class="hdi-section">
|
<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>
|
||||||
|
@ -26,7 +27,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 class="hdi-section">
|
<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.
|
||||||
|
@ -47,14 +48,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="hdi-footernotesection">
|
<section class="note">
|
||||||
<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,9 +1,10 @@
|
||||||
|
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 class="imprint">
|
<section>
|
||||||
<h1>Imprint</h1>
|
<h1>Imprint</h1>
|
||||||
<section>
|
<section>
|
||||||
<a href="/contact">
|
<a href="/contact">
|
||||||
|
@ -54,7 +55,7 @@ function imprint() {
|
||||||
</h5>
|
</h5>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</>
|
</Layout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
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 class="index">
|
<section>
|
||||||
<h1>li'l Judd</h1>
|
<h1>li'l Judd</h1>
|
||||||
<h5>The competetive Splatoon Bot</h5>
|
<h5>The competetive Splatoon Bot</h5>
|
||||||
<div>
|
<div>
|
||||||
|
@ -13,7 +14,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,
|
We may collect information on how you interact with our bot, including
|
||||||
including but not limited to:
|
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
|
- Consent: You have given your consent for the processing of your
|
||||||
your personal data for one or more specific purposes.
|
personal data for one or more specific purposes.
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
@ -111,9 +111,8 @@ 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
|
We do not sell, trade, or otherwise transfer your personal information
|
||||||
information to third parties. However, we may share your information
|
to third parties. However, we may share your information with:
|
||||||
with:
|
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
|
@ -151,8 +150,8 @@ function privacyPolicy() {
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<p>
|
<p>
|
||||||
- Right to erasure: You can request the deletion of your
|
- Right to erasure: You can request the deletion of your personal
|
||||||
personal data.
|
data.
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -160,8 +159,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
|
We may update this Privacy Policy to reflect changes in our practices.
|
||||||
practices. The updated version will be posted on
|
The updated version will be posted on
|
||||||
https://liljudd.ink/privacy-policy.
|
https://liljudd.ink/privacy-policy.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
@ -172,8 +171,7 @@ function privacyPolicy() {
|
||||||
please contact us at contact@moonleay.net.
|
please contact us at contact@moonleay.net.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</Layout>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
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 class="stack-title">The Stack</h1>
|
<h1>The Stack</h1>
|
||||||
<section class="stack-section">
|
<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>
|
||||||
|
@ -14,14 +15,14 @@ function stack() {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="stack-section">
|
<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 class="stack-section">
|
<section>
|
||||||
<img
|
<img
|
||||||
src="/assets/logos/kordextensions.png"
|
src="/assets/logos/kordextensions.png"
|
||||||
alt="The Kord-Extensions logo"
|
alt="The Kord-Extensions logo"
|
||||||
|
@ -31,7 +32,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 class="stack-section">
|
<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>
|
||||||
|
@ -47,7 +48,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
|
By inviting the bot and using its features (commands, planning system)
|
||||||
system) are you agreeing to the below mentioned Terms and Privacy
|
are you agreeing to the below mentioned Terms and Privacy Policy
|
||||||
Policy (Policy) of the bot.
|
(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
|
any Discord Server (Server) you share with it, that you can invite it
|
||||||
it to any Server that you have "Manage Server" rights for and that
|
to any Server that you have "Manage Server" rights for and that this
|
||||||
this privilege might get revoked for you, if you're subject of
|
privilege might get revoked for you, if you're subject of breaking the
|
||||||
breaking the terms and/or policy of this bot, or 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
|
Through Inviting the bot may it collect specific data as described in
|
||||||
in its Policy.
|
its Policy.
|
||||||
<br />
|
<br />
|
||||||
The intended usage of this data is for core functionalities of the
|
The intended usage of this data is for core functionalities of the bot
|
||||||
bot such as command handling, guild-specific settings and the
|
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
|
The bot may not be used by individuals under the minimal age described
|
||||||
described in Discord's Terms of Service.
|
in Discord's Terms of Service.
|
||||||
<br />
|
<br />
|
||||||
Doing so will be seen as a violation of these terms and will result
|
Doing so will be seen as a violation of these terms and will result in
|
||||||
in a removal of the bot from any servers you own.
|
a removal of the bot from any servers you own.
|
||||||
<br />
|
<br />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -60,8 +60,7 @@ 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
|
of any of Discord's assets, trademarks or other intellectual property.
|
||||||
property.
|
|
||||||
<br />
|
<br />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -71,26 +70,25 @@ 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
|
He has faith in the end users being truthfull about their information
|
||||||
information and not misusing this bot or the services of Discord Inc
|
and not misusing this bot or the services of Discord Inc in a
|
||||||
in a malicious way.
|
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
|
you're not agreeing with the new changes. You may opt out by Removing
|
||||||
Removing the bot from any Server you have the rights for.
|
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
|
through the official Support Discord of the Bot. Other ways of support
|
||||||
support may be provided but aren't guaranteed.
|
may be provided but aren't guaranteed.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Layout>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,46 +5,73 @@ nav {
|
||||||
backdrop-filter: blur(5px);
|
backdrop-filter: blur(5px);
|
||||||
position: sticky;
|
position: sticky;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
ul {
|
ul .navElem a {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
.textBx {
|
.primary {
|
||||||
display: flex;
|
opacity: 0;
|
||||||
align-items: center;
|
}
|
||||||
|
|
||||||
#logo {
|
.secondary {
|
||||||
|
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) {
|
||||||
ul {
|
justify-content: space-between;
|
||||||
flex-direction: row;
|
|
||||||
padding: 0 2rem;
|
|
||||||
|
|
||||||
.navElem:last-child {
|
ul {
|
||||||
margin-left: auto;
|
height: 72px;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,3 +53,24 @@ 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
.aboutdiv {
|
.about {
|
||||||
max-width: 1100px;
|
max-width: 1100px;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -1,38 +1,34 @@
|
||||||
.guildpfp {
|
.config {
|
||||||
|
.text-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guildpfp {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
}
|
|
||||||
|
|
||||||
.horizontal {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
h1 {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
}
|
||||||
p, h3, h4 {
|
|
||||||
|
label {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.marg_right_5px {
|
section,
|
||||||
margin-right: 10px;
|
a {
|
||||||
}
|
|
||||||
|
|
||||||
.centered {
|
|
||||||
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;
|
||||||
|
|
||||||
.contact {
|
section {
|
||||||
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;
|
||||||
|
|
||||||
.title {
|
h1 {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 1.2rem;
|
margin-bottom: 1.2rem;
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
.hdi-title {
|
.how-do-i {
|
||||||
|
h1 {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 1.2rem;
|
margin-bottom: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hdi-section {
|
section {
|
||||||
max-width: 1100px;
|
max-width: 1100px;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -39,9 +40,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.hdi-footernotesection {
|
.note {
|
||||||
max-width: 1100px;
|
max-width: 1100px;
|
||||||
margin: 1rem auto;
|
margin: 1rem auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -61,4 +62,5 @@
|
||||||
color: rgb(96 59 255) !important;
|
color: rgb(96 59 255) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
.stack-title {
|
.stack {
|
||||||
|
h1 {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 1.2rem;
|
margin-bottom: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stack-section {
|
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;
|
||||||
|
@ -33,9 +34,9 @@
|
||||||
align-self: center;
|
align-self: center;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.stack-note {
|
.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;
|
||||||
|
@ -58,4 +59,5 @@
|
||||||
color: rgb(96 59 255) !important;
|
color: rgb(96 59 255) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue