Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
andrecasal committed Jun 30, 2023
2 parents 752cd9b + 56d556b commit be311d4
Show file tree
Hide file tree
Showing 91 changed files with 4,789 additions and 1,752 deletions.
7 changes: 0 additions & 7 deletions .dockerignore

This file was deleted.

2 changes: 1 addition & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module.exports = {
fixStyle: 'inline-type-imports',
},
],
'@typescript-eslint/no-duplicate-imports': 'warn',
'import/no-duplicates': 'warn',
},
overrides: [
{
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ jobs:
file: 'fly.toml'
field: 'app'

# move Dockerfile to root
- name: 🚚 Move Dockerfile
run: |
mv ./other/Dockerfile ./Dockerfile
mv ./other/.dockerignore ./.dockerignore
- name: 🚀 Deploy Staging
if: ${{ github.ref == 'refs/heads/dev' }}
uses: superfly/[email protected]
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,4 @@ source library (appropriate attribution is appreciated). Then come back and make
a PR to use your new library.

NOTE: Actual adoption of your library is not guaranteed. Offloading maintenance
and adaptability is a delecate balance.
and adaptability is a delicate balance.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@
npx create-remix@latest --typescript --install --template epicweb-dev/epic-stack
```

[![The Epic Stack](https://github.com/epicweb-dev/epic-stack/assets/1500684/1b00286c-aa3d-44b2-9ef2-04f694eb3592)](https://www.epicweb.dev/epic-stack)
[![The Epic Stack](https://github-production-user-asset-6210df.s3.amazonaws.com/1500684/246885449-1b00286c-aa3d-44b2-9ef2-04f694eb3592.png)](https://www.epicweb.dev/epic-stack)

[The Epic Stack](https://www.epicweb.dev/epic-stack)

<hr />

## Watch Kent's Introduction to The Epic Stack

[![screenshot of a YouTube video](https://github.com/epicweb-dev/epic-stack/assets/1500684/6beafa78-41c6-47e1-b999-08d3d3e5cb57)](https://www.youtube.com/watch?v=yMK5SVRASxM)
[![screenshot of a YouTube video](https://github-production-user-asset-6210df.s3.amazonaws.com/1500684/242088051-6beafa78-41c6-47e1-b999-08d3d3e5cb57.png)](https://www.youtube.com/watch?v=yMK5SVRASxM)

["The Epic Stack" by Kent C. Dodds at #RemixConf 2023 💿](https://www.youtube.com/watch?v=yMK5SVRASxM)

Expand Down
22 changes: 22 additions & 0 deletions app/components/confetti.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Index as ConfettiShower } from 'confetti-react'
import { ClientOnly } from 'remix-utils'

/**
* confetti is a unique random identifier which re-renders the component
*/
export function Confetti({ confetti }: { confetti?: string }) {
return (
<ClientOnly>
{() => (
<ConfettiShower
key={confetti}
run={Boolean(confetti)}
recycle={false}
numberOfPieces={500}
width={window.innerWidth}
height={window.innerHeight}
/>
)}
</ClientOnly>
)
}
148 changes: 148 additions & 0 deletions app/components/forms.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { useInputEvent } from '@conform-to/react'
import React, { useId, useRef } from 'react'
import { Input } from '~/components/ui/input.tsx'
import { Label } from '~/components/ui/label.tsx'
import { Checkbox, type CheckboxProps } from '~/components/ui/checkbox.tsx'
import { Textarea } from '~/components/ui/textarea.tsx'

export type ListOfErrors = Array<string | null | undefined> | null | undefined

export function ErrorList({
id,
errors,
}: {
errors?: ListOfErrors
id?: string
}) {
const errorsToRender = errors?.filter(Boolean)
if (!errorsToRender?.length) return null
return (
<ul id={id} className="space-y-1">
{errorsToRender.map(e => (
<li key={e} className="text-[10px] text-foreground-danger">
{e}
</li>
))}
</ul>
)
}

export function Field({
labelProps,
inputProps,
errors,
className,
}: {
labelProps: Omit<React.LabelHTMLAttributes<HTMLLabelElement>, 'className'>
inputProps: Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className'>
errors?: ListOfErrors
className?: string
}) {
const fallbackId = useId()
const id = inputProps.id ?? fallbackId
const errorId = errors?.length ? `${id}-error` : undefined
return (
<div className={className}>
<Label htmlFor={id} {...labelProps} />
<Input
id={id}
aria-invalid={errorId ? true : undefined}
aria-describedby={errorId}
{...inputProps}
/>
<div className="min-h-[32px] px-4 pb-3 pt-1">
{errorId ? <ErrorList id={errorId} errors={errors} /> : null}
</div>
</div>
)
}

export function TextareaField({
labelProps,
textareaProps,
errors,
className,
}: {
labelProps: React.LabelHTMLAttributes<HTMLLabelElement>
textareaProps: React.InputHTMLAttributes<HTMLTextAreaElement>
errors?: ListOfErrors
className?: string
}) {
const fallbackId = useId()
const id = textareaProps.id ?? textareaProps.name ?? fallbackId
const errorId = errors?.length ? `${id}-error` : undefined
return (
<div className={className}>
<Label htmlFor={id} {...labelProps} />
<Textarea
id={id}
aria-invalid={errorId ? true : undefined}
aria-describedby={errorId}
{...textareaProps}
/>
<div className="px-4 pb-3 pt-1">
{errorId ? <ErrorList id={errorId} errors={errors} /> : null}
</div>
</div>
)
}

export function CheckboxField({
labelProps,
buttonProps,
errors,
className,
}: {
labelProps: JSX.IntrinsicElements['label']
buttonProps: CheckboxProps
errors?: ListOfErrors
className?: string
}) {
const fallbackId = useId()
const buttonRef = useRef<HTMLButtonElement>(null)
// To emulate native events that Conform listen to:
// See https://conform.guide/integrations
const control = useInputEvent({
// Retrieve the checkbox element by name instead as Radix does not expose the internal checkbox element
// See https://github.com/radix-ui/primitives/discussions/874
ref: () =>
buttonRef.current?.form?.elements.namedItem(buttonProps.name ?? ''),
onFocus: () => buttonRef.current?.focus(),
})
const id = buttonProps.id ?? buttonProps.name ?? fallbackId
const errorId = errors?.length ? `${id}-error` : undefined
return (
<div className={className}>
<div className="flex gap-2">
<Checkbox
id={id}
ref={buttonRef}
aria-invalid={errorId ? true : undefined}
aria-describedby={errorId}
{...buttonProps}
onCheckedChange={state => {
control.change(Boolean(state.valueOf()))
buttonProps.onCheckedChange?.(state)
}}
onFocus={event => {
control.focus()
buttonProps.onFocus?.(event)
}}
onBlur={event => {
control.blur()
buttonProps.onBlur?.(event)
}}
type="button"
/>
<label
htmlFor={id}
{...labelProps}
className="self-center text-body-xs text-muted-foreground"
/>
</div>
<div className="px-4 pb-3 pt-1">
{errorId ? <ErrorList id={errorId} errors={errors} /> : null}
</div>
</div>
)
}
7 changes: 7 additions & 0 deletions app/components/ui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# shadcn/ui

Some components in this directory are downloaded via the
[shadcn/ui](https://ui.shadcn.com) [CLI](https://ui.shadcn.com/docs/cli). Feel
free to customize them to your needs. It's important to know that shadcn/ui is
not a library of components you install, but instead it's a registry of prebuilt
components which you can download and customize.
58 changes: 58 additions & 0 deletions app/components/ui/button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import * as React from 'react'
import { Slot } from '@radix-ui/react-slot'
import { cva, type VariantProps } from 'class-variance-authority'

import { cn } from '~/utils/misc.ts'

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: {
default: '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: {
default: 'h-10 px-4 py-2',
wide: 'px-24 py-5',
sm: 'h-9 rounded-md px-3',
lg: 'h-11 rounded-md px-8',
pill: 'px-12 py-3 leading-3',
icon: 'h-10 w-10',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
},
)

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 }
36 changes: 36 additions & 0 deletions app/components/ui/checkbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as React from 'react'
import * as CheckboxPrimitive from '@radix-ui/react-checkbox'

import { cn } from '~/utils/misc.ts'

export type CheckboxProps = Omit<
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>,
'type'
> & {
type?: string
}

const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
>(({ className, ...props }, ref) => (
<CheckboxPrimitive.Root
ref={ref}
className={cn(
'peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
className,
)}
{...props}
>
<CheckboxPrimitive.Indicator
className={cn('flex items-center justify-center text-current')}
>
<svg viewBox="0 0 8 8">
<path d="M1,4 L3,6 L7,2" stroke="currentcolor" strokeWidth="1" fill="none" />
</svg>
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
))
Checkbox.displayName = CheckboxPrimitive.Root.displayName

export { Checkbox }
Loading

0 comments on commit be311d4

Please sign in to comment.