Skip to content

Instantly share code, notes, and snippets.

@tammyhart
Last active August 23, 2024 03:53
Show Gist options
  • Save tammyhart/11c366b08e65c5168abbb6b0e6c69abc to your computer and use it in GitHub Desktop.
Save tammyhart/11c366b08e65c5168abbb6b0e6c69abc to your computer and use it in GitHub Desktop.
Typed Component for <main>
import styled from "styled-components"
import type { Sizes } from "./styles"
import { mapGap, mapGrow, media, size } from "./utils"
const BIG = "big"
const NONE = "none"
const NORMAL = "normal"
const DEFAULT_SIZE = NORMAL
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const gapSizes = [BIG, NONE, NORMAL] as const
type GapSizes = (typeof gapSizes)[number]
type GapSettings = {
[key in GapSizes]: Sizes
}
const gap: GapSettings = {
[BIG]: [10, 20],
[NONE]: [0, 0],
[NORMAL]: [5, 5, 10],
}
type MainProps = {
$gap?: GapSizes
$grow?: number[]
$row?: boolean
}
const Main = styled.main<MainProps>`
display: flex;
flex-direction: column;
padding: 0 ${size(2)};
${({ $gap }) => mapGap(gap[$gap || DEFAULT_SIZE])}
${media.lap`
padding: 0 ${size(5)};
${({ $grow }: MainProps) => $grow && mapGrow($grow)}
`}
${({ $row }) => ($row ? media.desk`flex-direction: row;` : "")}
`
export default Main
export type Size =
| 0
| 0.25
| 0.5
| 0.75
| 1
| 1.25
| 1.5
| 1.75
| 2
| 2.5
| 3
| 3.5
| 4
| 4.5
| 5
| 6
| 7
| 8
| 10
| 15
| 18
| 20
| 25
| 30
| 40
| 100
| 110
| 150
| 180
export type Sizes = (null | Size)[]
export type Gap = SizeOptions
import { css } from "styled-components"
import type { Gap, Size } from "./styles"
export const size = (number: Size) => number * 8 + "px"
const LAP = "lap"
const DESK = "desk"
const deviceSizes = [LAP, DESK] as const
type DeviceSizes = (typeof deviceSizes)[number]
const device = {
[LAP]: size(100),
[DESK]: size(150),
}
const mediaStyles =
(deviceSize: DeviceSizes) =>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(literals: TemplateStringsArray, ...rest: any[]) =>
css`
@media (min-width: ${device[deviceSize]}) {
${css(literals, ...rest)};
}
`
export const media = {
[LAP]: mediaStyles(LAP),
[DESK]: mediaStyles(DESK),
}
export const mapGap = (gap: Gap) => {
gap = Array.isArray(gap) ? gap : [gap]
const property = (g: Size) => `gap: ${size(g)};`
return css`
${gap.map(
(g, i) =>
g &&
(i === 0 ? property(g) : media[deviceSizes[i - 1]]`${property(g)};`)
)}
`
}
export const mapGrow = (grow: number[]) =>
grow.map(
(number, i) =>
`> :nth-child(${i + 1}) { flex-basis: 0; flex-grow: ${number}; }`
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment