Skip to content

Commit

Permalink
Update solid start
Browse files Browse the repository at this point in the history
  • Loading branch information
filipw01 committed Mar 3, 2024
1 parent 08d48d2 commit da4e2e3
Show file tree
Hide file tree
Showing 38 changed files with 15,287 additions and 7,831 deletions.
20,418 changes: 13,893 additions & 6,525 deletions package-lock.json

Large diffs are not rendered by default.

27 changes: 13 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,33 @@
"name": "fiszki",
"type": "module",
"scripts": {
"build": "npm run build:css && solid-start build",
"build": "npm run build:css && vinxi build",
"build:css": "tailwindcss -m -i ./styles/app.css -o src/styles/app.css",
"deploy": "fly deploy --remote-only --env PORT='8080'",
"dev": "concurrently \"npm run dev:css\" \"solid-start dev\"",
"dev": "concurrently \"npm run dev:css\" \"vinxi dev\"",
"dev:css": "tailwindcss -w -i ./styles/app.css -o src/styles/app.css",
"test": "vitest",
"e2e": "playwright test",
"start": "solid-start start"
"start": "vinxi start"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.345.0",
"@iconify/json": "^2.2.74",
"@iconify/json": "^2.2.187",
"@motionone/solid": "^10.16.2",
"@prisma/client": "^4.15.0",
"@solidjs/meta": "^0.28.5",
"@solidjs/router": "^0.8.2",
"@solidjs/meta": "^0.29.2",
"@solidjs/router": "^0.12.4",
"@solidjs/start": "^0.6.0",
"bcryptjs": "^2.4.3",
"dotenv": "^16.1.4",
"js-confetti": "^0.11.0",
"lodash-es": "^4.17.21",
"nanoid": "^4.0.2",
"solid-devtools": "^0.27.1",
"solid-js": "^1.7.6",
"solid-start": "^0.2.26",
"solid-start-node": "^0.2.26",
"solid-devtools": "^0.29.3",
"solid-js": "^1.8.15",
"undici": "^5.22.1",
"unplugin-icons": "^0.16.2",
"unplugin-icons": "^0.18.5",
"vinxi": "^0.3.4",
"zod": "^3.21.4"
},
"devDependencies": {
Expand All @@ -39,15 +39,14 @@
"@vitest/coverage-c8": "^0.31.4",
"autoprefixer": "^10.4.14",
"concurrently": "^8.1.0",
"esbuild": "^0.17.19",
"esbuild-register": "^3.4.2",
"esbuild": "^0.20.1",
"esbuild-register": "^3.5.0",
"eslint": "^8.42.0",
"postcss": "^8.4.24",
"prettier": "^2.8.8",
"prisma": "^4.15.0",
"tailwindcss": "^3.3.2",
"typescript": "^5.1.3",
"vite": "^4.3.9",
"vitest": "^0.31.4"
},
"engines": {
Expand Down
Binary file removed public/favicon.ico
Binary file not shown.
22 changes: 22 additions & 0 deletions src/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// @refresh reload
import { Suspense } from 'solid-js'
import { Router } from '@solidjs/router'
import { MetaProvider } from '@solidjs/meta'
import { FileRoutes } from '@solidjs/start'
import './styles/app.css'
import './styles/index.css'
import './styles/global.css'

export default function App() {
return (
<Router
root={(props) => (
<MetaProvider>
<Suspense fallback={<div>Loading</div>}>{props.children}</Suspense>
</MetaProvider>
)}
>
<FileRoutes />
</Router>
)
}
3 changes: 1 addition & 2 deletions src/components/Flashcard.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import catImage from '~/assets/cat.png'
import { TagList } from '~/components/TagList'
import { Tag } from '~/utils.server'
import { A } from 'solid-start'
import { createEffect, createMemo, JSX, Show } from 'solid-js'
import { Motion } from '@motionone/solid'
import JSConfetti from 'js-confetti'
Expand Down Expand Up @@ -92,7 +91,7 @@ export const Flashcard = (props: Props) => {
>
<Show when={props.isEditable}>
<div class="absolute top-2 right-2 text-sm lg:text-lg">
<A href={`/flashcards/edit/${props.id}`}>Edit</A>
<a href={`/flashcards/edit/${props.id}`}>Edit</a>
</div>
</Show>
<ConditionalButton onClick={props.onClick}>
Expand Down
5 changes: 2 additions & 3 deletions src/components/Folder/Folder.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { FolderIcon } from '~/components/FolderIcon'
import { A } from 'solid-start'
import styles from './Folder.module.css'

type Props = {
Expand All @@ -11,14 +10,14 @@ type Props = {

export const Folder = (props: Props) => {
return (
<A href={props.nameLink} class={styles.card}>
<a href={props.nameLink} class={styles.card}>
<div class={styles.icon} style={{ '--icon-color': props.color }}>
<FolderIcon width={42} height={34} />
</div>
<div class={styles.textWrapper}>
<p class={styles.name}>{props.name}</p>
<p class={styles.counter}>{props.count + ' flashcards'}</p>
</div>
</A>
</a>
)
}
5 changes: 2 additions & 3 deletions src/components/HeadingWithCreate.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { A } from 'solid-start'
import { Heading } from '~/components/base/Heading'
import AddIcon from '~icons/ri/add-fill'

export const HeadingWithCreate = (props: { children: string; url: string }) => {
return (
<div class="flex gap-3 items-center">
<Heading>{props.children}</Heading>
<A href={props.url} class="h-6 w-6 bg-blue rounded-full text-white block">
<a href={props.url} class="h-6 w-6 bg-blue rounded-full text-white block">
<AddIcon class="w-6 h-6" />
</A>
</a>
</div>
)
}
2 changes: 1 addition & 1 deletion src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { JSX } from 'solid-js'
import { useSidebarVisibility } from '~/routes/(app)'
import { clsx } from '~/utils'
import { useSidebarVisibility } from '~/components/SidebarVisibilityContext'

export const Sidebar = (props: { children: JSX.Element }) => {
const [isSidebarOpen] = useSidebarVisibility()
Expand Down
15 changes: 15 additions & 0 deletions src/components/SidebarVisibilityContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Accessor, createContext, Setter, useContext } from 'solid-js'

const SidebarVisibilityContext =
createContext<[Accessor<boolean>, Setter<boolean>]>()

export const SidebarVisibilityProvider = SidebarVisibilityContext.Provider
export const useSidebarVisibility = () => {
const value = useContext(SidebarVisibilityContext)
if (!value) {
throw new Error(
'useSidebarVisibility must be used within SidebarVisibilityContext'
)
}
return value
}
152 changes: 83 additions & 69 deletions src/components/Study.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,79 +8,80 @@ import { TagList } from '~/components/TagList'
import { LetterButton } from '~/components/LetterButton'
import { Button } from '~/components/base/Button'
import { Flashcard } from './Flashcard'
import { createServerAction$ } from 'solid-start/server'
import { requireUserEmail } from '~/session.server'
import { requireUserEmail } from '~/server/session.server'
import { db } from '~/db/db.server'
import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js'
import { isServer } from 'solid-js/web'
import { shuffle } from 'lodash-es'
import { action, useSubmission } from '@solidjs/router'

interface Props {
flashcards: FlashcardType[]
}

export const Study = (props: Props) => {
const [isRepeating, { Form: RepeatForm }] = createServerAction$(
async (_form: FormData, { request }) => {
const email = await requireUserEmail(request)
const flashcardsInSession = await db.learningSession.findFirst({
const repeat = action(async () => {
'use server'

const email = await requireUserEmail()
const flashcardsInSession = await db.learningSession.findFirst({
where: {
ownerEmail: email,
},
select: {
uncompletedFlashcards: {
select: {
id: true,
},
},
},
})
const shuffledFlashcards = shuffle(
flashcardsInSession?.uncompletedFlashcards ?? []
)
await db.$transaction(
shuffledFlashcards.map((flashcard, index) => {
return db.flashcard.update({
where: {
ownerEmail: email,
id: flashcard.id,
},
select: {
uncompletedFlashcards: {
select: {
id: true,
},
},
data: {
learningSessionSortingIndex: index,
},
})
const shuffledFlashcards = shuffle(
flashcardsInSession?.uncompletedFlashcards ?? []
)
await db.$transaction(
shuffledFlashcards.map((flashcard, index) => {
return db.flashcard.update({
where: {
id: flashcard.id,
},
data: {
learningSessionSortingIndex: index,
},
})
})
)
}
})
)
// TODO: probably this doesn't work without page refresh
})

const [isSubmitting, { Form }] = createServerAction$(
async (form: FormData, { request }) => {
const email = await requireUserEmail(request)
const rawFlashcardId = form.get('flashcardId')
const id = isNonEmptyString(rawFlashcardId) ? rawFlashcardId : null
const action = form.get('_action')
if (id !== null) {
db.flashcard.findFirstOrThrow({
where: {
id,
owner: {
email,
},
},
})
if (action === 'success') {
await actionSuccess(id, email)
}
if (action === 'failure') {
await actionFailure(id)
}
}
return null
},
{
invalidate: [], // we want to keep today's flashcards already fetched
const check = action(async (form: FormData) => {
'use server'

const email = await requireUserEmail()
const rawFlashcardId = form.get('flashcardId')
const id = isNonEmptyString(rawFlashcardId) ? rawFlashcardId : null
const action = form.get('_action')
if (id !== null) {
db.flashcard.findFirstOrThrow({
where: {
id,
owner: {
email,
},
},
})
if (action === 'success') {
await actionSuccess(id, email)
}
)
if (action === 'failure') {
await actionFailure(id)
}
}
return null
})
export const Study = (props: Props) => {
const isRepeating = useSubmission(repeat)
const isSubmitting = useSubmission(check)

const flashcardsCount = createMemo(() => props.flashcards.length)
let input: HTMLTextAreaElement | undefined
const [typedCorrectly, setTypedCorrectly] = createSignal<boolean | null>(null)
Expand All @@ -98,7 +99,6 @@ export const Study = (props: Props) => {
input.focus()
}
})
setCurrentFlashcardIndex((prevIndex) => prevIndex + 1)
}

const handleCheck = () => {
Expand All @@ -120,10 +120,14 @@ export const Study = (props: Props) => {
fallback={
<div>
No flashcards left
<RepeatForm onSubmit={() => setCurrentFlashcardIndex(0)}>
<form
action={repeat}
method="post"
onSubmit={() => setCurrentFlashcardIndex(0)}
>
<Show when={isRepeating.pending}>Repeating...</Show>
<Button color="check">Rinse and repeat</Button>
</RepeatForm>
</form>
</div>
}
>
Expand Down Expand Up @@ -225,21 +229,29 @@ export const Study = (props: Props) => {
position="right"
color="skip"
size="small"
onClick={nextFlashcard}
onClick={() => {
nextFlashcard()
setCurrentFlashcardIndex((prevIndex) => prevIndex + 1)
}}
>
skip
</Button>
</div>
) : (
<div class="flex">
{isSubmitting.pending && <div>Submitting...</div>}
{isSubmitting.error && (
<div>Error: {isSubmitting.error.message}</div>
)}
{/*{isSubmitting.error && (*/}
{/* <div>Error: {isSubmitting.error.message}</div>*/}
{/*)}*/}
{!typedCorrectly() && (
<Form
<form
action={check}
method="post"
class="basis-0 flex-grow flex-shrink"
onSubmit={nextFlashcard}
onSubmit={() => {
nextFlashcard()
setCurrentFlashcardIndex((prevIndex) => prevIndex + 1)
}}
>
<input
type="hidden"
Expand All @@ -254,9 +266,11 @@ export const Study = (props: Props) => {
>
wrong
</Button>
</Form>
</form>
)}
<Form
<form
action={check}
method="post"
class="basis-0 flex-grow flex-shrink"
onSubmit={nextFlashcard}
>
Expand All @@ -273,7 +287,7 @@ export const Study = (props: Props) => {
correct
</Button>
)}
</Form>
</form>
</div>
)}
</div>
Expand Down
Loading

0 comments on commit da4e2e3

Please sign in to comment.