Skip to content

Commit

Permalink
Refresh the template
Browse files Browse the repository at this point in the history
  • Loading branch information
iamyuu committed Apr 5, 2024
1 parent 86513c9 commit 05aa47e
Show file tree
Hide file tree
Showing 85 changed files with 3,569 additions and 17,031 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VITE_API_URL=
VITE_API_URL=https://api.backend.mock
30 changes: 0 additions & 30 deletions .eslintrc.js

This file was deleted.

63 changes: 63 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: CI

on:
push:
branches:
- main
paths:
- 'app/**'

pull_request:
branches:
- main
types:
- opened
- reopened
- synchronize
- ready_for_review
paths:
- 'app/**'

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
quality:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup Biome
uses: biomejs/setup-biome@v2
with:
version: latest

- name: Run Biome
run: biome ci .

test:
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [21]
fail-fast: false

steps:
- uses: actions/checkout@v4

- uses: pnpm/action-setup@v3

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'

- name: Install dependencies
run: pnpm install

- name: Test
run: pnpm run test
4 changes: 0 additions & 4 deletions .husky/pre-commit

This file was deleted.

2 changes: 1 addition & 1 deletion .node-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
lts-hydrogen
21
8 changes: 0 additions & 8 deletions .vscode/extensions.json

This file was deleted.

30 changes: 0 additions & 30 deletions .vscode/settings.json

This file was deleted.

38 changes: 35 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,43 @@
npx degit iamyuu/vitr
```

## Libraries

- [shadcn/ui](https://ui.shadcn.com/) - UI components
- [TanStack Router](https://tanstack.com/router/v1) - Client side routing
- [TanStack Query](https://tanstack.com/query/v4) - Asynchronous state management
- [ky](https://github.com/sindresorhus/ky) - HTTP client
- [react-hook-form](https://react-hook-form.com) - Form state management
- [Zod](https://zod.dev) - Validation with static type inference

## Available Scripts

- `pnpm setup`: Setup the project.
- `pnpm run dev`: Runs the app in the development mode.
- `pnpm run build`: Build the app to the production mode.
- `pnpm run preview`: Preview the app in the production mode.
- `pnpm run lint`: Lint the code.
- `pnpm run format`: Formitize the code.
- `pnpm run lint`: Check code quality
- `pnpm run type-check`: Check type errors

## Project Structure

```
app
├── assets # static assets, fonts, etc
├── components # shared components used across the entire application
├── constants # global configuration, env variables, etc
├── features # feature based modules
│ └── {awesome-features}
│ ├── components # components scoped to a specific feature
│ ├── schemas # zod schema for a specific feature
│ ├── services # exported API request declarations and api hooks related to a specific feature
│ ├── stores # state stores for a specific feature
│ └── types # typescript types for TS specific feature
├── generated # generated files
├── hooks # shared hooks used across the entire application
├── libs # configuration for external libraries
├── providers # all of the application providers
├── routes # screen that will show to user
├── styles # global styling and theme configuration
├── types # base types used accross the application
└── utils # shared utility functions
```
27 changes: 27 additions & 0 deletions app/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { RouterProvider } from "@tanstack/react-router";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { router } from "~/libs/router";
import { AppProviders } from "~/providers/app-providers";
import "~/styles/global.css";

function App() {
// We put the RouterProvider here instead of in app-providers
// because we want to exclude that from the test environment
return <RouterProvider router={router} />;
}

/**
* Render the App with AppProviders
*
* @param root - The root element to render the app into it
*/
export function renderApp(root: HTMLElement) {
createRoot(root).render(
<StrictMode>
<AppProviders>
<App />
</AppProviders>
</StrictMode>,
);
}
File renamed without changes.
11 changes: 11 additions & 0 deletions app/components/fallback/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// import type { ErrorComponentProps } from "@tanstack/react-router";

// export function ErrorFallback(props: ErrorComponentProps) {
// return (
// <div role="alert" className="p-2">
// {props.error instanceof Error ? props.error.message : "An error occurred"}
// </div>
// );
// }

export { ErrorComponent as ErrorFallback } from "@tanstack/react-router";
3 changes: 3 additions & 0 deletions app/components/fallback/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./error";
export * from "./not-found";
export * from "./pending";
10 changes: 10 additions & 0 deletions app/components/fallback/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { NotFoundRouteProps } from "@tanstack/react-router";

export function NotFoundFallback(props: NotFoundRouteProps) {
return (
<div className="p-2">
<h1>Not Found</h1>
<p>The page you are looking for does not exist.</p>
</div>
);
}
10 changes: 10 additions & 0 deletions app/components/fallback/pending.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export function PendingFallback() {
return (
<div
aria-label="Loading"
className="p-2 text-2xl inline-block animate-spin transition opacity-1 duration-500 delay-300"
>
</div>
);
}
61 changes: 61 additions & 0 deletions app/components/form/form-field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Slot } from "@radix-ui/react-slot";
import * as React from "react";
import type { FieldValues, UseFormGetFieldState } from "react-hook-form";
import { Label } from "~/components/ui/label";

export interface FormFieldProps
extends React.HTMLAttributes<HTMLElement>,
ReturnType<UseFormGetFieldState<FieldValues>> {
label: string;
description?: string;
}

export const FormField = React.forwardRef<HTMLElement, FormFieldProps>(
({ invalid, isDirty, isTouched, isValidating, error, ...props }, ref) => {
const id = React.useId();
const formItemId = `${id}-form-item`;
const formMessageId = `${id}-form-item-message`;
const formDescriptionId = props?.description
? `${id}-form-item-description`
: "";

return (
<div className="space-y-2">
<Label
className={invalid ? "text-destructive" : ""}
htmlFor={formItemId}
>
{props.label}
</Label>

<Slot
ref={ref}
id={formItemId}
aria-describedby={
!invalid
? `${formDescriptionId}`
: `${formDescriptionId} ${formMessageId}`
}
aria-invalid={!!invalid}
{...props}
/>

{props?.description ? (
<p id={formDescriptionId} className="text-sm text-muted-foreground">
{props.description}
</p>
) : null}

{invalid ? (
<p
id={formMessageId}
className="text-sm font-medium text-destructive"
>
{error?.message}
</p>
) : null}
</div>
);
},
);
FormField.displayName = "FormField";
1 change: 1 addition & 0 deletions app/components/form/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./form-field";
55 changes: 55 additions & 0 deletions app/components/ui/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Slot } from "@radix-ui/react-slot";
import { type VariantProps, cva } from "class-variance-authority";
import * as React from "react";
import { cn } from "~/utils/misc";

const buttonVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
solid: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
sm: "h-9 rounded-md px-3",
md: "h-10 px-4 py-2",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "solid",
size: "md",
},
},
);

export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
);
},
);
Button.displayName = "Button";

export { Button, buttonVariants };
3 changes: 3 additions & 0 deletions app/components/ui/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./button";
export * from "./input";
export * from "./label";
Loading

0 comments on commit 05aa47e

Please sign in to comment.