Cleanup. Fix simple linter error.
This commit is contained in:
parent
ca1a2bf1ca
commit
9138a187a9
2 changed files with 32 additions and 36 deletions
|
|
@ -34,6 +34,7 @@ export default tseslint.config(
|
|||
"error",
|
||||
{ prefer: "type-imports", fixStyle: "inline-type-imports" },
|
||||
],
|
||||
"@typescript-eslint/consistent-type-definitions": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
|
|
|
|||
67
src/App.tsx
67
src/App.tsx
|
|
@ -10,24 +10,12 @@ import {
|
|||
DialogContent,
|
||||
} from "@mui/material"
|
||||
|
||||
// TODO: Use Material UI later.
|
||||
// TODO: Improve error-handling. Introduce some proper server response.
|
||||
|
||||
// For better type-error messages when you have inexhaustive switch cases.
|
||||
function assertNever(value: never): never {
|
||||
throw new Error(`Unexpected value: ${value}`)
|
||||
}
|
||||
|
||||
// === Image ===
|
||||
type ImageId = string
|
||||
type ImageRef = string
|
||||
|
||||
type Image = {
|
||||
id: ImageId
|
||||
dimension: Dimension
|
||||
source: ImageRef
|
||||
}
|
||||
|
||||
// === Dimension ===
|
||||
|
||||
type Dimension = {
|
||||
|
|
@ -35,8 +23,11 @@ type Dimension = {
|
|||
height: number
|
||||
}
|
||||
const Dimension = {
|
||||
medium: { width: 180, height: 180 } as Dimension,
|
||||
big: { width: 720, height: 720 } as Dimension,
|
||||
medium: { width: 180, height: 180 },
|
||||
big: { width: 720, height: 720 },
|
||||
} satisfies {
|
||||
medium: Dimension
|
||||
big: Dimension
|
||||
}
|
||||
|
||||
// === Page ===
|
||||
|
|
@ -69,7 +60,7 @@ const Page = {
|
|||
},
|
||||
// for hashing in maps to avoid identity problems
|
||||
key(page: Page): PageKey {
|
||||
return `${page.page}:${page.limit}`
|
||||
return `${String(page.page)}:${String(page.limit)}`
|
||||
},
|
||||
isFirst(page: Page): boolean {
|
||||
return page.page === FIRST_PAGE
|
||||
|
|
@ -88,9 +79,11 @@ const picsumApiImageSchema = z.object({
|
|||
type PicsumApiImage = z.infer<typeof picsumApiImageSchema>
|
||||
|
||||
async function getPicsumImages({ page, limit }: Page): Promise<PicsumApiImage[]> {
|
||||
const response = await fetch(`https://picsum.photos/v2/list?limit=${limit}&page=${page}`)
|
||||
const response = await fetch(
|
||||
`https://picsum.photos/v2/list?limit=${String(limit)}&page=${String(page)}`,
|
||||
)
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch images: ${response.status}`)
|
||||
throw new Error(`Failed to fetch images: ${String(response.status)}`)
|
||||
}
|
||||
|
||||
const json: unknown = await response.json()
|
||||
|
|
@ -99,16 +92,6 @@ async function getPicsumImages({ page, limit }: Page): Promise<PicsumApiImage[]>
|
|||
return data
|
||||
}
|
||||
|
||||
// TODO: We don't really need this.
|
||||
async function getImages(page: Page): Promise<Image[]> {
|
||||
const data = await getPicsumImages(page)
|
||||
return data.map(({ id, download_url, width, height }) => ({
|
||||
id: id as ImageId,
|
||||
dimension: { width, height },
|
||||
source: download_url as ImageRef,
|
||||
}))
|
||||
}
|
||||
|
||||
async function getImageIds(page: Page): Promise<ImageId[]> {
|
||||
const data = await getPicsumImages(page)
|
||||
return data.map(({ id }) => id)
|
||||
|
|
@ -116,7 +99,7 @@ async function getImageIds(page: Page): Promise<ImageId[]> {
|
|||
|
||||
// Use this for `<img src=... />`
|
||||
function getImageSource(id: ImageId, dimension: Dimension): ImageRef {
|
||||
return `https://picsum.photos/id/${id}/${dimension.width}/${dimension.height}`
|
||||
return `https://picsum.photos/id/${id}/${String(dimension.width)}/${String(dimension.height)}`
|
||||
}
|
||||
|
||||
// === Generic Remote Data ===
|
||||
|
|
@ -218,7 +201,7 @@ function useApp(): [State, Dispatch] {
|
|||
return { ...state, selectedImage: undefined }
|
||||
}
|
||||
default:
|
||||
return assertNever(msg)
|
||||
return msg satisfies never
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -254,10 +237,10 @@ function imageGridStyle(dimension: Dimension) {
|
|||
return {
|
||||
display: "grid",
|
||||
gridTemplateColumns: {
|
||||
xs: `repeat(2, ${dimension.width}px)`,
|
||||
md: `repeat(5, ${dimension.width}px)`,
|
||||
xs: `repeat(2, ${String(dimension.width)}px)`,
|
||||
md: `repeat(5, ${String(dimension.width)}px)`,
|
||||
},
|
||||
gridAutoRows: `${dimension.height}px`,
|
||||
gridAutoRows: `${String(dimension.height)}px`,
|
||||
gap: 2,
|
||||
}
|
||||
}
|
||||
|
|
@ -287,7 +270,9 @@ function Images({ images }: { images: ImageId[] }) {
|
|||
<Box
|
||||
component="img"
|
||||
src={getImageSource(imageId, Dimension.medium)}
|
||||
onClick={() => dispatch({ tag: "imageClicked", imageId })}
|
||||
onClick={() => {
|
||||
dispatch({ tag: "imageClicked", imageId })
|
||||
}}
|
||||
sx={{
|
||||
width: Dimension.medium.width,
|
||||
height: Dimension.medium.height,
|
||||
|
|
@ -307,7 +292,9 @@ function ImageModal({ selectedImage }: { selectedImage: ImageId | undefined }) {
|
|||
return (
|
||||
<Dialog
|
||||
open={selectedImage !== undefined}
|
||||
onClose={() => dispatch({ tag: "modalCloseButtonClicked" })}
|
||||
onClose={() => {
|
||||
dispatch({ tag: "modalCloseButtonClicked" })
|
||||
}}
|
||||
maxWidth={false}
|
||||
>
|
||||
<DialogContent sx={{ p: 0, overflow: "hidden" }}>
|
||||
|
|
@ -359,7 +346,9 @@ export default function App() {
|
|||
}}
|
||||
>
|
||||
<Button
|
||||
onClick={() => dispatch({ tag: "previousButtonClicked" })}
|
||||
onClick={() => {
|
||||
dispatch({ tag: "previousButtonClicked" })
|
||||
}}
|
||||
disabled={Page.isFirst(state.page)}
|
||||
>
|
||||
prev
|
||||
|
|
@ -374,7 +363,13 @@ export default function App() {
|
|||
>
|
||||
{state.page.page}
|
||||
</Typography>
|
||||
<Button onClick={() => dispatch({ tag: "nextButtonClicked" })}>next</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
dispatch({ tag: "nextButtonClicked" })
|
||||
}}
|
||||
>
|
||||
next
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue