Compare commits
2 commits
ddf138ab99
...
9f43138252
Author | SHA1 | Date | |
---|---|---|---|
|
9f43138252 | ||
|
144221bb2f |
16 changed files with 2484 additions and 409 deletions
|
@ -1,10 +1,27 @@
|
|||
/* eslint-env node */
|
||||
module.exports = {
|
||||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: ['@typescript-eslint'],
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:solid/typescript",
|
||||
"plugin:prettier/recommended",
|
||||
"plugin:import/recommended",
|
||||
"plugin:import/typescript",
|
||||
],
|
||||
parser: "@typescript-eslint/parser",
|
||||
plugins: ["@typescript-eslint", "solid", "prettier", "import"],
|
||||
root: true,
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-function-return-type": "warn"
|
||||
}
|
||||
settings: {
|
||||
"import/resolver": {
|
||||
typescript: {
|
||||
project: "./tsconfig.json",
|
||||
},
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/explicit-function-return-type": "error",
|
||||
"no-duplicate-imports": ["error", { includeExports: true }],
|
||||
"import/no-unresolved": "error",
|
||||
"import/no-named-as-default-member": "off",
|
||||
},
|
||||
};
|
||||
|
|
18
client-solid/.prettierrc
Normal file
18
client-solid/.prettierrc
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"plugins": [
|
||||
"@trivago/prettier-plugin-sort-imports",
|
||||
"prettier-plugin-tailwindcss"
|
||||
],
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"bracketSameLine": false,
|
||||
"importOrder": [
|
||||
"<THIRD_PARTY_MODULES>",
|
||||
"^(@api|@assets|@ui)(/.*)$",
|
||||
"^[.]"
|
||||
],
|
||||
"importOrderSeparation": true,
|
||||
"importOrderSortSpecifiers": true
|
||||
}
|
2667
client-solid/package-lock.json
generated
2667
client-solid/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -6,19 +6,28 @@
|
|||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"fmt": "prettier --config .prettierrc 'src/**/*.ts' 'src/**/*.tsx' --write && npx eslint --fix 'src/**/*.ts' 'src/**/*.tsx'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@solidjs/router": "^0.9.1",
|
||||
"solid-js": "^1.8.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^6.10.0",
|
||||
"@typescript-eslint/parser": "^6.10.0",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.11.0",
|
||||
"@typescript-eslint/parser": "^6.11.0",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"daisyui": "^4.0.1",
|
||||
"eslint": "^8.53.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.29.0",
|
||||
"eslint-plugin-prettier": "^5.0.1",
|
||||
"eslint-plugin-solid": "^0.13.0",
|
||||
"postcss": "^8.4.31",
|
||||
"prettier": "^3.1.0",
|
||||
"prettier-plugin-tailwindcss": "^0.5.7",
|
||||
"tailwindcss": "^3.3.5",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^4.5.0",
|
||||
|
|
|
@ -8,7 +8,7 @@ export function Arrow(): JSXElement {
|
|||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
class="h-6 w-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
|
@ -20,7 +20,7 @@ export function Arrow(): JSXElement {
|
|||
}
|
||||
|
||||
export function loadSpinner(): JSXElement {
|
||||
return <span class="loading loading-spinner loading-lg self-center"></span>;
|
||||
return <span class="loading loading-spinner loading-lg self-center" />;
|
||||
}
|
||||
|
||||
// Hamburger menu icon
|
||||
|
@ -32,7 +32,7 @@ export function Bars(): JSXElement {
|
|||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
class="h-6 w-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
|
@ -51,7 +51,7 @@ export function UserCircle(): JSXElement {
|
|||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
class="h-6 w-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
|
@ -70,7 +70,7 @@ export function Flake(): JSXElement {
|
|||
stroke-width="1"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
class="w-8 h-8"
|
||||
class="h-8 w-8"
|
||||
data-testid="AcUnitIcon"
|
||||
>
|
||||
<path d="M22 11h-4.17l3.24-3.24-1.41-1.42L15 11h-2V9l4.66-4.66-1.42-1.41L13 6.17V2h-2v4.17L7.76 2.93 6.34 4.34 11 9v2H9L4.34 6.34 2.93 7.76 6.17 11H2v2h4.17l-3.24 3.24 1.41 1.42L9 13h2v2l-4.66 4.66 1.42 1.41L11 17.83V22h2v-4.17l3.24 3.24 1.42-1.41L13 15v-2h2l4.66 4.66 1.41-1.42L17.83 13H22z" />
|
||||
|
@ -86,7 +86,7 @@ export function Plus(): JSXElement {
|
|||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
class="h-6 w-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
|
@ -105,7 +105,7 @@ export function Home(): JSXElement {
|
|||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
class="h-6 w-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
import { JSXElement, Show, onCleanup, useContext } from "solid-js";
|
||||
import { ModalContext } from "./Root";
|
||||
|
||||
import { LoginForm } from "./RegLogin/Login";
|
||||
import { RegisterForm } from "./RegLogin/Register";
|
||||
import { ModalContext } from "./Root";
|
||||
|
||||
export function LoginModal(): JSXElement {
|
||||
const modal_ctx = useContext(ModalContext);
|
||||
|
||||
if (!modal_ctx) {
|
||||
// Handle the case where ModalContext is not available
|
||||
return null;
|
||||
}
|
||||
const modal_ctx = useContext(ModalContext)!;
|
||||
|
||||
const closeModal = (): void => {
|
||||
modal_ctx.setLoginModalOpen(false);
|
||||
|
@ -26,13 +22,13 @@ export function LoginModal(): JSXElement {
|
|||
<div class="modal-box">
|
||||
<form method="dialog">
|
||||
<button
|
||||
onclick={closeModal}
|
||||
class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2"
|
||||
onClick={closeModal}
|
||||
class="btn btn-circle btn-ghost btn-sm absolute right-2 top-2"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</form>
|
||||
<h3 class="font-bold text-lg mb-2">Welcome!</h3>
|
||||
<h3 class="mb-2 text-lg font-bold">Welcome!</h3>
|
||||
<div class="tabs tabs-lifted">
|
||||
<input
|
||||
type="radio"
|
||||
|
@ -41,7 +37,7 @@ export function LoginModal(): JSXElement {
|
|||
aria-label="Login"
|
||||
checked
|
||||
/>
|
||||
<div class="tab-content bg-base-100 border-base-300 rounded-box p-10">
|
||||
<div class="tab-content rounded-box border-base-300 bg-base-100 p-10">
|
||||
<LoginForm />
|
||||
</div>
|
||||
|
||||
|
@ -51,13 +47,13 @@ export function LoginModal(): JSXElement {
|
|||
class="tab"
|
||||
aria-label="Register"
|
||||
/>
|
||||
<div class="tab-content bg-base-100 border-base-300 rounded-box p-10">
|
||||
<div class="tab-content rounded-box border-base-300 bg-base-100 p-10">
|
||||
<RegisterForm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form method="dialog" class="modal-backdrop">
|
||||
<button onclick={closeModal}>close</button>
|
||||
<button onClick={closeModal}>close</button>
|
||||
</form>
|
||||
</dialog>
|
||||
</Show>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { JSXElement, Show, useContext } from "solid-js";
|
||||
import { A } from "@solidjs/router";
|
||||
import { LoginContext } from "./Root";
|
||||
import { ModalContext } from "./Root";
|
||||
import { JSXElement, Show, useContext } from "solid-js";
|
||||
|
||||
import { Flake, Home, Plus, UserCircle } from "./Icons";
|
||||
import { LoginContext, ModalContext } from "./Root";
|
||||
|
||||
// Represents a single list item in the menu bar
|
||||
function MenuItem(props: { href: string; children: JSXElement }): JSXElement {
|
||||
|
@ -19,7 +19,7 @@ function MenuItem(props: { href: string; children: JSXElement }): JSXElement {
|
|||
function Menu(): JSXElement {
|
||||
const login_ctx = useContext(LoginContext);
|
||||
return (
|
||||
<ul class="menu md:menu-horizontal space-y-2 md:space-x-2 md:space-y-0 rounded-box">
|
||||
<ul class="menu space-y-2 rounded-box md:menu-horizontal md:space-x-2 md:space-y-0">
|
||||
<MenuItem href="/">
|
||||
<Home />
|
||||
</MenuItem>
|
||||
|
@ -49,9 +49,9 @@ export function Navbar(): JSXElement {
|
|||
};
|
||||
|
||||
return (
|
||||
<div class="navbar text-neutral-content max-w-3xl max-w rounded-box md:my-4">
|
||||
<div class="max-w navbar max-w-3xl rounded-box text-neutral-content md:my-4">
|
||||
<div class="flex-1">
|
||||
<A href={"/"} class="btn btn-ghost normal-case pl-1 text-xl">
|
||||
<A href={"/"} class="btn btn-ghost pl-1 text-xl normal-case">
|
||||
<Flake />
|
||||
FrostByte
|
||||
</A>
|
||||
|
@ -59,10 +59,10 @@ export function Navbar(): JSXElement {
|
|||
<div class="flex">
|
||||
<Menu />
|
||||
</div>
|
||||
<div class="flex-1 justify-end flex">
|
||||
<div class="flex flex-1 justify-end">
|
||||
<A
|
||||
href="#"
|
||||
class="btn btn-ghost capitalize pr-1 text-sm"
|
||||
class="btn btn-ghost pr-1 text-sm capitalize"
|
||||
onClick={clickHandler}
|
||||
>
|
||||
{
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { JSXElement, Show, createSignal, onMount, useContext } from "solid-js";
|
||||
import { createPost } from "./api";
|
||||
import { NewPost } from "./api";
|
||||
import { useNavigate } from "@solidjs/router";
|
||||
import { JSXElement, Show, createSignal, onMount, useContext } from "solid-js";
|
||||
|
||||
import { LoginContext } from "./Root";
|
||||
import { NewPost, createPost } from "./api";
|
||||
|
||||
export function NewPostInputArea(): JSXElement {
|
||||
const [content, setContent] = createSignal("");
|
||||
|
@ -35,25 +35,23 @@ export function NewPostInputArea(): JSXElement {
|
|||
return (
|
||||
<Show
|
||||
when={!waiting()}
|
||||
fallback={
|
||||
<span class="loading loading-spinner loading-lg self-center"></span>
|
||||
}
|
||||
fallback={<span class="loading loading-spinner loading-lg self-center" />}
|
||||
>
|
||||
<div class="flex flex-col w-full space-y-2">
|
||||
<div class="flex w-full flex-col space-y-2">
|
||||
<textarea
|
||||
class="textarea textarea-bordered h-32"
|
||||
placeholder="Speak your mind..."
|
||||
maxLength={500}
|
||||
oninput={(input): void => {
|
||||
onInput={(input): void => {
|
||||
setContent(input.target.value);
|
||||
}}
|
||||
></textarea>
|
||||
/>
|
||||
<button
|
||||
class={
|
||||
"btn btn-primary self-end btn-sm" +
|
||||
"btn btn-primary btn-sm self-end" +
|
||||
(content() == "" ? " btn-disabled" : "")
|
||||
}
|
||||
onclick={sendPost}
|
||||
onClick={sendPost}
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { JSXElement, Show, createSignal, For } from "solid-js";
|
||||
import { getPosts } from "./api";
|
||||
import { Post } from "./api";
|
||||
import { useNavigate } from "@solidjs/router";
|
||||
import { Arrow } from "./Icons";
|
||||
import { loadSpinner } from "./Icons";
|
||||
import { For, JSXElement, Show, createSignal } from "solid-js";
|
||||
|
||||
import { Arrow, loadSpinner } from "./Icons";
|
||||
import { Post, getPosts } from "./api";
|
||||
|
||||
export function Posts(): JSXElement {
|
||||
const [posts, setPosts] = createSignal([] as Post[]);
|
||||
|
@ -17,22 +16,22 @@ export function Posts(): JSXElement {
|
|||
return (
|
||||
<Show when={!loading()} fallback={loadSpinner()}>
|
||||
<For each={posts()}>
|
||||
{(post): JSXElement => <PostSegment post={post}></PostSegment>}
|
||||
{(post): JSXElement => <PostSegment post={post} />}
|
||||
</For>
|
||||
</Show>
|
||||
);
|
||||
}
|
||||
|
||||
// This is the card container for a post
|
||||
export function PostSegment({ post }: { post: Post }): JSXElement {
|
||||
export function PostSegment(props: { post: Post }): JSXElement {
|
||||
const nav = useNavigate();
|
||||
return (
|
||||
<div class="card border-b-2 flex-grow border-b-base-300 bg-base-200 hover:bg-base-300 transition-all compact text-base-content w-full">
|
||||
<div class="card compact w-full flex-grow border-b-2 border-b-base-300 bg-base-200 text-base-content transition-all hover:bg-base-300">
|
||||
<div class="card-body">
|
||||
<p class="text-base-content break-words">{post?.content}</p>
|
||||
<p class="break-words text-base-content">{props.post?.content}</p>
|
||||
<div class="card-actions justify-end">
|
||||
<button
|
||||
onClick={(): void => nav("/post/" + post?.id)}
|
||||
onClick={(): void => nav("/post/" + props.post?.id)}
|
||||
class="btn btn-xs"
|
||||
>
|
||||
<Arrow />
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { Route, Routes } from "@solidjs/router";
|
||||
import { JSXElement } from "solid-js";
|
||||
|
||||
import { NewPostInputArea } from "./NewPost";
|
||||
import { Posts } from "./Posts";
|
||||
import { SinglePost } from "./SinglePost";
|
||||
import { NewPostInputArea } from "./NewPost";
|
||||
import { JSXElement } from "solid-js";
|
||||
|
||||
// Primary is the section of the page that holds the main content
|
||||
export function Primary(): JSXElement {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { JSXElement, createSignal, useContext } from "solid-js";
|
||||
|
||||
import { LoginContext, ModalContext } from "../Root";
|
||||
|
||||
export function LoginForm(): JSXElement {
|
||||
|
@ -20,7 +21,7 @@ export function LoginForm(): JSXElement {
|
|||
async function loginPress(e: Event): Promise<void> {
|
||||
e.preventDefault();
|
||||
setWaiting(true);
|
||||
submitLogin(username(), password()).then((token) => {
|
||||
submitLogin(username(), password()).then((token): void => {
|
||||
if (token != "") {
|
||||
setWaiting(false);
|
||||
setError(false);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { JSXElement, createSignal, useContext } from "solid-js";
|
||||
|
||||
import { LoginContext, ModalContext } from "../Root";
|
||||
|
||||
export function RegisterForm(): JSXElement {
|
||||
|
@ -21,7 +22,8 @@ export function RegisterForm(): JSXElement {
|
|||
async function regPress(e: Event): Promise<void> {
|
||||
e.preventDefault();
|
||||
setWaiting(true);
|
||||
submitRegistration(username(), password(), captcha()).then((token) => {
|
||||
submitRegistration(username(), password(), captcha()).then(
|
||||
(token): void => {
|
||||
if (token != "") {
|
||||
setWaiting(false);
|
||||
setError(false);
|
||||
|
@ -33,7 +35,8 @@ export function RegisterForm(): JSXElement {
|
|||
} else {
|
||||
loginFailed();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { Accessor, JSXElement, createSignal } from "solid-js";
|
||||
import { createContext } from "solid-js";
|
||||
import { Accessor, JSXElement, createContext, createSignal } from "solid-js";
|
||||
|
||||
import { LoginModal } from "./LoginModal";
|
||||
import { Navbar } from "./Navbar";
|
||||
import { Primary } from "./Primary";
|
||||
import { LoginModal } from "./LoginModal";
|
||||
|
||||
// Representing the state of varoious modals.
|
||||
// So far we only have one modal, but we can add more later
|
||||
|
@ -44,7 +43,7 @@ function Root(): JSXElement {
|
|||
<div class="flex flex-col items-center">
|
||||
<Navbar />
|
||||
<LoginModal />
|
||||
<div class="flex flex-col items-center w-full md:max-w-3xl px-2 space-y-2">
|
||||
<div class="flex w-full flex-col items-center space-y-2 px-2 md:max-w-3xl">
|
||||
<Primary />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { useParams } from "@solidjs/router";
|
||||
import { JSXElement, Show, Suspense, createResource } from "solid-js";
|
||||
import { getPost } from "./api";
|
||||
import { PostSegment } from "./Posts";
|
||||
|
||||
import { loadSpinner } from "./Icons";
|
||||
import { PostSegment } from "./Posts";
|
||||
import { getPost } from "./api";
|
||||
|
||||
export function SinglePost(): JSXElement {
|
||||
const params = useParams();
|
||||
|
@ -11,7 +12,7 @@ export function SinglePost(): JSXElement {
|
|||
return (
|
||||
<Suspense fallback={loadSpinner()}>
|
||||
<Show when={post()}>
|
||||
<PostSegment post={post()!}></PostSegment>
|
||||
<PostSegment post={post()!} />
|
||||
</Show>
|
||||
</Suspense>
|
||||
);
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
/* @refresh reload */
|
||||
import { Router } from "@solidjs/router";
|
||||
import { render } from "solid-js/web";
|
||||
|
||||
import "./index.css";
|
||||
import Root from "./Root";
|
||||
|
||||
import { Router } from "@solidjs/router";
|
||||
import "./index.css";
|
||||
|
||||
const root = document.getElementById("root");
|
||||
|
||||
|
|
Loading…
Reference in a new issue