Skip to content

Commit

Permalink
just some light refactoring this fine friday
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanflorence committed Nov 3, 2023
1 parent 4bd2783 commit 55bf1bc
Show file tree
Hide file tree
Showing 32 changed files with 445 additions and 443 deletions.
Empty file removed app/auth/cookie.ts
Empty file.
14 changes: 14 additions & 0 deletions app/components/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { forwardRef } from "react";

export let Button = forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement>
>((props, ref) => {
return (
<button
{...props}
ref={ref}
className="flex w-full justify-center rounded-md bg-brand-blue px-1 py-1 text-sm font-semibold leading-6 text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-blue"
/>
);
});
46 changes: 46 additions & 0 deletions app/components/input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { forwardRef, useId } from "react";

export let Input = forwardRef<
HTMLInputElement,
React.InputHTMLAttributes<HTMLInputElement>
>((props, ref) => {
return (
<input
{...props}
ref={ref}
className="form-input block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-brand-blue sm:text-sm sm:leading-6"
/>
);
});

export let Label = forwardRef<
HTMLLabelElement,
React.LabelHTMLAttributes<HTMLLabelElement>
>((props, ref) => {
return (
<label
{...props}
ref={ref}
className="block text-sm font-medium leading-6 text-gray-900"
/>
);
});

export let LabeledInput = forwardRef<
HTMLInputElement,
React.InputHTMLAttributes<HTMLInputElement> & {
label: React.ReactNode;
id?: string;
}
>(({ id, label, ...props }, ref) => {
let uid = useId();
id = id ?? uid;
return (
<>
<Label htmlFor={id}>{label}</Label>
<div className="mt-2">
<Input {...props} ref={ref} id={id} />
</div>
</>
);
});
2 changes: 1 addition & 1 deletion app/icons/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function Icon({

export function LoginIcon() {
return (
<svg className="inline self-center w-8 h-8 text-white">
<svg className="inline self-center w-8 h-8 text-white transform scale-x-[-1]">
<use href={`${iconsHref}#login`} />
</svg>
);
Expand Down
21 changes: 0 additions & 21 deletions app/modules/create-form.ts

This file was deleted.

6 changes: 4 additions & 2 deletions app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import {
type ShouldRevalidateFunctionArgs,
Link,
} from "@remix-run/react";
import "./styles.css";
import { redirect, type DataFunctionArgs } from "@remix-run/node";

import { LoginIcon, LogoutIcon } from "./icons/icons";
import { getAuthFromRequest } from "./auth/auth";
import { redirect, type DataFunctionArgs } from "@remix-run/node";

import "./styles.css";

export async function loader({ request }: DataFunctionArgs) {
let auth = await getAuthFromRequest(request);
Expand Down
4 changes: 0 additions & 4 deletions app/routes/board.$id/CONTENT_TYPES.ts

This file was deleted.

113 changes: 113 additions & 0 deletions app/routes/board.$id/board.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { useRef } from "react";
import invariant from "tiny-invariant";
import { useFetchers, useLoaderData } from "@remix-run/react";

import { type loader } from "./server";
import { INTENTS, type RenderedItem } from "./types";
import { Column } from "./column";
import { NewColumn } from "./new-column";

export function Board() {
let { board } = useLoaderData<typeof loader>();

let itemsById = new Map(board.items.map((item) => [item.id, item]));
let pendingItems = usePendingItems();

// merge pending items and existing items
for (let pendingItem of pendingItems) {
let item = itemsById.get(pendingItem.id);
let merged = item
? { ...item, ...pendingItem }
: { ...pendingItem, boardId: board.id };
itemsById.set(pendingItem.id, merged);
}

// merge pending and existing columns
let optAddingColumns = useAddingColumns();
type Column = (typeof board.columns)[0] | (typeof optAddingColumns)[0];
type ColumnWithItems = Column & { items: typeof board.items };
let columns = [...board.columns, ...optAddingColumns].reduce(
(map, column) => map.set(String(column.id), { ...column, items: [] }),
new Map<string, ColumnWithItems>(),
);

// add items to their columns
for (let item of itemsById.values()) {
let columnId = item.columnId;
let column = columns.get(columnId);
invariant(column, "missing column");
column.items.push(item);
}

let scrollContainerRef = useRef<HTMLDivElement>(null);
function scrollRight() {
invariant(scrollContainerRef.current);
scrollContainerRef.current.scrollLeft =
scrollContainerRef.current.scrollWidth;
}

return (
<div
className="h-full min-h-0 flex flex-col overflow-x-scroll"
ref={scrollContainerRef}
style={{ backgroundColor: board.color }}
>
<h1 className="px-8 my-4 text-2xl font-medium">{board.name}</h1>

<div className="flex flex-grow min-h-0 h-full items-start gap-4 px-8 pb-4">
{[...columns.values()].map((col) => {
return (
<Column
key={col.id}
name={col.name}
columnId={col.id}
items={col.items}
/>
);
})}

<NewColumn
boardId={board.id}
onAdd={scrollRight}
editInitially={board.columns.length === 0}
/>

<div data-lol-shutup className="w-8 h-1 flex-shrink-0" />
</div>
</div>
);
}
function useAddingColumns() {
type CreateColumnFetcher = ReturnType<typeof useFetchers>[0] & {
formData: FormData;
};

return useFetchers()
.filter((fetcher): fetcher is CreateColumnFetcher => {
return fetcher.formData?.get("intent") === INTENTS.createColumn;
})
.map((fetcher) => {
let name = String(fetcher.formData.get("name"));
let id = String(fetcher.formData.get("id"));
return { name, id };
});
}
function usePendingItems() {
type PendingItem = ReturnType<typeof useFetchers>[0] & {
formData: FormData;
};
return useFetchers()
.filter((fetcher): fetcher is PendingItem => {
if (!fetcher.formData) return false;
let intent = fetcher.formData.get("intent");
return intent === INTENTS.createItem || intent === INTENTS.moveItem;
})
.map((fetcher) => {
let columnId = String(fetcher.formData.get("columnId"));
let title = String(fetcher.formData.get("title"));
let id = String(fetcher.formData.get("id"));
let order = Number(fetcher.formData.get("order"));
let item: RenderedItem = { title, id, order, columnId, content: null };
return item;
});
}
8 changes: 4 additions & 4 deletions app/routes/board.$id/card.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { flushSync } from "react-dom";
import invariant from "tiny-invariant";
import { useSubmit } from "@remix-run/react";
import { useState } from "react";
import { INTENTS, ItemMutation } from "./mutations";
import invariant from "tiny-invariant";
import { CONTENT_TYPES } from "./CONTENT_TYPES";
import { flushSync } from "react-dom";

import { ItemMutation, INTENTS, CONTENT_TYPES } from "./types";

interface CardProps {
title: string;
Expand Down
13 changes: 8 additions & 5 deletions app/routes/board.$id/column.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { useState, useEffect, useRef } from "react";
import { useFetcher, useSubmit } from "@remix-run/react";

import { Icon } from "../../icons/icons";

import { INTENTS, ItemMutation } from "./mutations";
import { Icon } from "~/icons/icons";

import {
ItemMutation,
INTENTS,
CONTENT_TYPES,
type RenderedItem,
} from "./types";
import invariant from "tiny-invariant";
import { NewCard } from "./new-card";
import { flushSync } from "react-dom";
import { CONTENT_TYPES } from "./CONTENT_TYPES";
import { Card } from "./card";
import type { RenderedItem } from "./types";

interface ColumnProps {
name: string;
Expand Down
27 changes: 27 additions & 0 deletions app/routes/board.$id/components.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { forwardRef } from "react";

export let SaveButton = forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement>
>((props, ref) => {
return (
<button
ref={ref}
{...props}
className="text-sm rounded-lg text-left p-2 font-medium text-white bg-brand-blue"
/>
);
});

export let CancelButton = forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement>
>((props, ref) => {
return (
<button
ref={ref}
{...props}
className="text-sm rounded-lg text-left p-2 font-medium hover:bg-slate-200 focus:bg-slate-200"
/>
);
});
46 changes: 0 additions & 46 deletions app/routes/board.$id/mutations.ts

This file was deleted.

22 changes: 5 additions & 17 deletions app/routes/board.$id/new-card.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useRef, useState } from "react";
import { useRef } from "react";
import invariant from "tiny-invariant";
import { Form, useSubmit } from "@remix-run/react";
import { INTENTS } from "./mutations";

import { ItemMutationFields } from "./mutations";
import { INTENTS, ItemMutationFields } from "./types";
import { SaveButton, CancelButton } from "./components";

export function NewCard({
columnId,
Expand Down Expand Up @@ -82,20 +82,8 @@ export function NewCard({
}}
/>
<div className="flex justify-between">
<button
ref={buttonRef}
type="submit"
className="text-sm rounded-lg text-left p-2 font-medium text-white bg-brand-blue"
>
Save Card
</button>
<button
type="button"
onClick={onComplete}
className="text-sm rounded-lg text-left p-2 font-medium hover:bg-slate-200 focus:bg-slate-200"
>
Cancel
</button>
<SaveButton ref={buttonRef}>Save Card</SaveButton>
<CancelButton onClick={onComplete}>Cancel</CancelButton>
</div>
</Form>
);
Expand Down
Loading

0 comments on commit 55bf1bc

Please sign in to comment.