24 | 28 | Epic Stack 29 | 42 | 43 |
44 |45 | Check the{' '} 46 | 50 | Getting Started 51 | {' '} 52 | guide file for how to get your project off the ground! 53 |
54 |18 | {error.status} {error.data} 19 |
20 | ), 21 | statusHandlers, 22 | unexpectedErrorHandler = error =>{getErrorMessage(error)}
, 23 | }: { 24 | defaultStatusHandler?: StatusHandler 25 | statusHandlers?: Record32 | {location.pathname} 33 |34 |
45 | Check the{' '} 46 | 50 | Getting Started 51 | {' '} 52 | guide file for how to get your project off the ground! 53 |
54 |48 | Disabling two factor authentication is not recommended. However, if 49 | you would like to do so, click here: 50 |
51 |
55 |
66 |
71 | Two factor authentication adds an extra layer of security to your 72 | account. You will need to enter a code from an authenticator app 73 | like{' '} 74 | 75 | 1Password 76 | {' '} 77 | to log in. 78 |
79 |Select a note
8 |No user with the username "{params.username}" exists
95 | ), 96 | }} 97 | /> 98 | ) 99 | } 100 | -------------------------------------------------------------------------------- /app/styles/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | :root { 7 | --font-sans: Nunito Sans, Nunito Sans Fallback; 8 | /* --font-mono: here if you got it... */ 9 | 10 | /* prefixed with foreground because it should look good on the background */ 11 | --foreground-destructive: 345 82.7% 40.8%; 12 | 13 | --background: 0 0% 100%; 14 | --foreground: 222.2 84% 4.9%; 15 | 16 | --muted: 210 40% 93%; 17 | --muted-foreground: 215.4 16.3% 30%; 18 | 19 | --popover: 0 0% 100%; 20 | --popover-foreground: 222.2 84% 4.9%; 21 | 22 | --card: 0 0% 100%; 23 | --card-foreground: 222.2 84% 4.9%; 24 | 25 | --border: 214.3 31.8% 91.4%; 26 | --input: 214.3 31.8% 91.4%; 27 | --input-invalid: 0 84.2% 60.2%; 28 | 29 | --primary: 222.2 47.4% 11.2%; 30 | --primary-foreground: 210 40% 98%; 31 | 32 | --secondary: 210 20% 83%; 33 | --secondary-foreground: 222.2 47.4% 11.2%; 34 | 35 | --accent: 210 40% 90%; 36 | --accent-foreground: 222.2 47.4% 11.2%; 37 | 38 | --destructive: 0 70% 50%; 39 | --destructive-foreground: 210 40% 98%; 40 | 41 | --ring: 215 20.2% 65.1%; 42 | 43 | --radius: 0.5rem; 44 | } 45 | 46 | .dark { 47 | --background: 222.2 84% 4.9%; 48 | --foreground: 210 40% 98%; 49 | 50 | /* prefixed with foreground because it should look good on the background */ 51 | --foreground-destructive: -4 84% 60%; 52 | 53 | --muted: 217.2 32.6% 12%; 54 | --muted-foreground: 215 20.2% 65.1%; 55 | 56 | --popover: 222.2 84% 4.9%; 57 | --popover-foreground: 210 40% 98%; 58 | 59 | --card: 222.2 84% 4.9%; 60 | --card-foreground: 210 40% 98%; 61 | 62 | --border: 217.2 32.6% 17.5%; 63 | --input: 217.2 32.6% 17.5%; 64 | --input-invalid: 0 62.8% 30.6%; 65 | 66 | --primary: 210 40% 98%; 67 | --primary-foreground: 222.2 47.4% 11.2%; 68 | 69 | --secondary: 217.2 20% 24%; 70 | --secondary-foreground: 210 40% 98%; 71 | 72 | --accent: 217.2 32.6% 10%; 73 | --accent-foreground: 210 40% 98%; 74 | 75 | --destructive: 0 60% 40%; 76 | --destructive-foreground: 0 85.7% 97.3%; 77 | 78 | --ring: 217.2 32.6% 60%; 79 | } 80 | } 81 | 82 | @layer base { 83 | * { 84 | @apply border-border; 85 | } 86 | body { 87 | @apply bg-background text-foreground; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/utils/confetti.server.ts: -------------------------------------------------------------------------------- 1 | import { redirect } from '@remix-run/node' 2 | import * as cookie from 'cookie' 3 | import { combineHeaders } from './misc.tsx' 4 | 5 | const cookieName = 'en_confetti' 6 | 7 | export function getConfetti(request: Request) { 8 | const cookieHeader = request.headers.get('cookie') 9 | const confettiId = cookieHeader 10 | ? cookie.parse(cookieHeader)[cookieName] 11 | : null 12 | return { 13 | confettiId, 14 | headers: confettiId ? createConfettiHeaders(null) : null, 15 | } 16 | } 17 | 18 | /** 19 | * This defaults the value to something reasonable if you want to show confetti. 20 | * If you want to clear the cookie, pass null and it will make a set-cookie 21 | * header that will delete the cookie 22 | * 23 | * @param value the value for the cookie in the set-cookie header 24 | * @returns Headers with a set-cookie header set to the value 25 | */ 26 | export function createConfettiHeaders( 27 | value: string | null = String(Date.now()), 28 | ) { 29 | return new Headers({ 30 | 'set-cookie': cookie.serialize(cookieName, value ? value : '', { 31 | path: '/', 32 | maxAge: value ? 60 : -1, 33 | }), 34 | }) 35 | } 36 | 37 | export async function redirectWithConfetti(url: string, init?: ResponseInit) { 38 | return redirect(url, { 39 | ...init, 40 | headers: combineHeaders(init?.headers, await createConfettiHeaders()), 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /app/utils/connections.server.ts: -------------------------------------------------------------------------------- 1 | import { createCookieSessionStorage } from '@remix-run/node' 2 | import { type ProviderName } from './connections.tsx' 3 | import { GitHubProvider } from './providers/github.server.ts' 4 | import { type AuthProvider } from './providers/provider.ts' 5 | import { type Timings } from './timing.server.ts' 6 | 7 | export const connectionSessionStorage = createCookieSessionStorage({ 8 | cookie: { 9 | name: 'en_connection', 10 | sameSite: 'lax', 11 | path: '/', 12 | httpOnly: true, 13 | maxAge: 60 * 10, // 10 minutes 14 | secrets: process.env.SESSION_SECRET.split(','), 15 | secure: process.env.NODE_ENV === 'production', 16 | }, 17 | }) 18 | 19 | export const providers: Record