Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d0425bbbf | ||
|
|
e28cd85934 |
@@ -48,15 +48,13 @@ const GridBlockComponent: React.FC<
|
||||
}
|
||||
else {
|
||||
let defaultSet = false
|
||||
for (const [key, value] of Object.entries(grid.at)) {
|
||||
for (const [key, value] of Object.entries(grid.at as typeof grid.at)) {
|
||||
if (!defaultSet) {
|
||||
// ts brain fart!
|
||||
clx += gridClx(value as GridColumnSpec)
|
||||
clx += gridClx(value)
|
||||
defaultSet = true
|
||||
}
|
||||
else {
|
||||
// ts brain fart!
|
||||
clx += gridClx(value as GridColumnSpec, `${key}:`)
|
||||
clx += gridClx(value, `${key}:`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
import React from 'react'
|
||||
import Image from 'next/image'
|
||||
|
||||
import type { Dimensions } from '../../types'
|
||||
import type { ImageBlock } from '../def'
|
||||
import { constrain, containsToken, cn } from '../../util'
|
||||
import { getConstaintsClx, containsToken, cn } from '../../util'
|
||||
|
||||
import type BlockComponentProps from './block-component-props'
|
||||
|
||||
|
||||
const ImageBlockComponent: React.FC<BlockComponentProps & {
|
||||
constraint?: Dimensions
|
||||
}> = ({
|
||||
const ImageBlockComponent: React.FC<BlockComponentProps> = ({
|
||||
block,
|
||||
className='',
|
||||
agent,
|
||||
constraint
|
||||
agent
|
||||
}) => {
|
||||
|
||||
if (block.blockType !== 'image') {
|
||||
@@ -25,6 +20,7 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
|
||||
src,
|
||||
alt,
|
||||
dim,
|
||||
constraints,
|
||||
props,
|
||||
fullWidthOnMobile,
|
||||
svgFillClass,
|
||||
@@ -35,9 +31,8 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
|
||||
|
||||
const toSpread: any = {}
|
||||
if (props?.fill === undefined) {
|
||||
const dimCon = (constraint ? constrain(dim, constraint) : dim)
|
||||
toSpread.width = dimCon.w
|
||||
toSpread.height = dimCon.h
|
||||
toSpread.width = dim.w
|
||||
toSpread.height = dim.h
|
||||
}
|
||||
|
||||
let _alt: string
|
||||
@@ -52,6 +47,8 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
|
||||
|
||||
const _svgFillClass = svgFillClass ?? ''
|
||||
|
||||
let constraintsClx = ''
|
||||
|
||||
// TODO: use two elements with 'md:hidden' for 3/4 size
|
||||
// https://nextjs.org/docs/app/building-your-application/optimizing/images#responsive
|
||||
if (agent === 'phone' ) {
|
||||
@@ -60,7 +57,6 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
|
||||
style: {
|
||||
width: '100%',
|
||||
height: 'auto',
|
||||
maxWidth: '420px'
|
||||
},
|
||||
sizes: '100vw',
|
||||
}
|
||||
@@ -74,6 +70,10 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
else if (constraints && ('xs' in constraints || 'w' in constraints)) {
|
||||
constraintsClx = getConstaintsClx(constraints, 'xs')
|
||||
}
|
||||
// last stop-gap
|
||||
else if (!specified('mobile-no-scale')) {
|
||||
if (props?.style?.width === 'auto' && typeof props.style.height === 'number' ) {
|
||||
props.style.height = props.style.height *.75
|
||||
@@ -89,6 +89,11 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
constraintsClx = getConstaintsClx(constraints)
|
||||
}
|
||||
|
||||
const stopGapClx = constraintsClx ? 'mx-auto ' : ''
|
||||
|
||||
const right = containsToken(specifiers, 'right')
|
||||
const center = containsToken(specifiers, 'center')
|
||||
@@ -97,10 +102,22 @@ const ImageBlockComponent: React.FC<BlockComponentProps & {
|
||||
|
||||
return (props?.fill) ? (
|
||||
<div className='relative w-full h-full'>
|
||||
<Image src={src} alt={_alt} {...toSpread} {...props} className={cn(_svgFillClass, 'max-w-[70vw] mx-auto', className)}/>
|
||||
<Image
|
||||
src={src}
|
||||
alt={_alt}
|
||||
{...toSpread}
|
||||
{...props}
|
||||
className={cn(_svgFillClass, stopGapClx, constraintsClx, className)}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<Image src={src} alt={_alt} {...toSpread} {...props} className={cn(alignSelfClx, _svgFillClass, 'max-w-[70vw] mx-auto', className)}/>
|
||||
<Image
|
||||
src={src}
|
||||
alt={_alt}
|
||||
{...toSpread}
|
||||
{...props}
|
||||
className={cn(alignSelfClx, _svgFillClass, stopGapClx, constraintsClx, className)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ const ScreenfulComponent: React.FC<{
|
||||
narrowGutters ?
|
||||
'px-6 lg:px-8 2xl:px-2 pb-6 pt-15 md:pt-26 lg:pt-28 '
|
||||
:
|
||||
'px-[8vw] xl:px-[1vw] pb-[8vh] pt-[calc(44px+4vh)] md:pt-[calc(80px+6vh)] ',
|
||||
'px-[8vw] xl:px-[1vw] pb-[8vh] pt-[calc(44px+3vh)] md:pt-[calc(80px+6vh)] ',
|
||||
|
||||
(agent && agent !== 'desktop') ? 'pt-15 sm:pt-17 pb-0 px-3 sm:px-8' : ''
|
||||
]
|
||||
|
||||
@@ -41,9 +41,8 @@ const SpaceBlockComponent: React.FC<BlockComponentProps> = ({
|
||||
ldMerge(_sizes, SPACE_DEFAULTS, b.sizes)
|
||||
|
||||
let clx = ''
|
||||
for (const [key, value] of Object.entries(_sizes)) {
|
||||
// ts brain fart!
|
||||
clx += `${key}:h-${value as TWSpaceUnit} `
|
||||
for (const [key, value] of Object.entries(_sizes as typeof _sizes)) {
|
||||
clx += `${key}:h-${value} `
|
||||
}
|
||||
|
||||
if (b.test) {
|
||||
|
||||
@@ -22,7 +22,12 @@ interface ImageBlock extends Block, ImageDef {
|
||||
sizes?: string
|
||||
/** if true, any alignement specifiers are ignored */
|
||||
fill?: boolean
|
||||
style?: any
|
||||
style?: {
|
||||
objectFit?: string
|
||||
objectPosition?: string
|
||||
width?: number | string
|
||||
height?: number | string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,24 @@
|
||||
// https://tailwindcss.com/docs/content-configuration#dynamic-class-names
|
||||
import screenDef from './screens.tailwind'
|
||||
|
||||
const screens = Object.keys(screenDef)
|
||||
|
||||
const fulls = () => {
|
||||
const r = []
|
||||
r.push('w-full')
|
||||
r.push('max-w-full')
|
||||
r.push('h-full')
|
||||
r.push('max-h-full')
|
||||
screens.forEach((sc) => {
|
||||
r.push(`${sc}:w-full`)
|
||||
r.push(`${sc}:max-w-full`)
|
||||
r.push(`${sc}:h-full`)
|
||||
r.push(`${sc}:max-h-full`)
|
||||
})
|
||||
return r
|
||||
}
|
||||
|
||||
|
||||
// https://tailwindcss.com/docs/content-configuration#dynamic-class-names
|
||||
// https://tailwindcss.com/docs/content-configuration#safelisting-classes
|
||||
export default [
|
||||
|
||||
@@ -7,7 +27,7 @@ export default [
|
||||
pattern: /grid-cols-[1-6]/,
|
||||
variants: [ 'xs', 'sm', 'md', 'lg', 'xl', '2xl' ]
|
||||
},
|
||||
{ // SpaceBlock
|
||||
{ // SpaceBlock h-1 through h-40
|
||||
pattern: /h-([0-9]|[1-3][0-9]|40)/,
|
||||
variants: [ 'xs', 'sm', 'md', 'lg', 'xl', '2xl' ]
|
||||
},
|
||||
@@ -17,6 +37,40 @@ export default [
|
||||
{ // EnhHeadingBlock
|
||||
pattern: /mb-([1-9]|1[0-2])/
|
||||
},
|
||||
// util/index: getConstraintClx() w-1 --> w-256, and h-1 --> h-256
|
||||
// util/index: getConstraintClx() w-[1%] --> w-[100%] and h-[1%] --> h-[100%]
|
||||
// https://github.com/tailwindlabs/tailwindcss/discussions/7908
|
||||
...[...Array(256).keys()].flatMap((i) => {
|
||||
const r = []
|
||||
r.push(`max-w-${i}`)
|
||||
r.push(`max-h-${i}`)
|
||||
screens.forEach((sc) => {
|
||||
r.push(`${sc}:max-w-${i}`)
|
||||
r.push(`${sc}:max-h-${i}`)
|
||||
})
|
||||
return r
|
||||
}),
|
||||
...[...Array(99).keys()].flatMap((i) => {
|
||||
const r = []
|
||||
r.push(`max-w-[${i}%]`)
|
||||
r.push(`max-h-[${i}%]`)
|
||||
screens.forEach((sc) => {
|
||||
r.push(`${sc}:max-w-[${i}%]`)
|
||||
r.push(`${sc}:max-h-[${i}%]`)
|
||||
})
|
||||
return r
|
||||
}),
|
||||
...fulls(),
|
||||
/*
|
||||
{ // util/index: getConstraintClx() w-1 --> w-256, and h-1 --> h-256
|
||||
pattern: /(w|h)-([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-6])/
|
||||
},
|
||||
{
|
||||
// util/index: getConstraintClx() w-[1%] --> w-[256]
|
||||
pattern: /(w|h)-\[([1-9]|[1-9][0-9]|100)%\]/
|
||||
},
|
||||
*/
|
||||
|
||||
'md:text-left', // EnhHeadingBlock
|
||||
'md:text-center',
|
||||
'md:text-right',
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
export default {
|
||||
/*
|
||||
if rem = 16px
|
||||
256 tw units is enough to specify up to
|
||||
1024px in 4px (0.25rem) increments.
|
||||
If one needs more than that, one can
|
||||
use screen sizes to define constraints.
|
||||
eg, 'max-w-screen-lg'
|
||||
*/
|
||||
const MAX = 256
|
||||
|
||||
const sp = {
|
||||
px: '1px',
|
||||
0: '0px',
|
||||
0.5: '0.125rem',
|
||||
@@ -7,51 +17,19 @@ export default {
|
||||
2: '0.5rem',
|
||||
2.5: '0.625rem',
|
||||
3: '0.75rem',
|
||||
3.5: '0.875rem',
|
||||
4: '1rem',
|
||||
5: '1.25rem',
|
||||
6: '1.5rem',
|
||||
7: '1.75rem',
|
||||
8: '2rem',
|
||||
9: '2.25rem',
|
||||
10: '2.5rem',
|
||||
11: '2.75rem',
|
||||
12: '3rem',
|
||||
13: '3.25rem',
|
||||
14: '3.5rem',
|
||||
15: '3.75rem',
|
||||
16: '4rem',
|
||||
17: '4.25rem',
|
||||
18: '4.5rem',
|
||||
19: '4.75rem',
|
||||
20: '5rem',
|
||||
21: '5.25rem',
|
||||
22: '5.5rem',
|
||||
23: '5.75rem',
|
||||
24: '6rem',
|
||||
25: '5.25rem',
|
||||
26: '5.5rem',
|
||||
27: '5.75rem',
|
||||
28: '7rem',
|
||||
29: '7.25rem',
|
||||
30: '7.5rem',
|
||||
31: '7.75rem',
|
||||
32: '8rem',
|
||||
33: '8.25rem',
|
||||
34: '8.5rem',
|
||||
35: '8.75rem',
|
||||
36: '9rem',
|
||||
37: '9.25rem',
|
||||
38: '9.5rem',
|
||||
39: '9.75rem',
|
||||
40: '10rem',
|
||||
44: '11rem',
|
||||
48: '12rem',
|
||||
52: '13rem',
|
||||
56: '14rem',
|
||||
60: '15rem',
|
||||
64: '16rem',
|
||||
72: '18rem',
|
||||
80: '20rem',
|
||||
96: '24rem',
|
||||
3.5: '0.875rem'
|
||||
}
|
||||
|
||||
for (let i = 4; i <= MAX; i++) {
|
||||
|
||||
const twoPlaces = Math.round(((i * 0.25) + Number.EPSILON) * 100) / 100
|
||||
|
||||
if (Number.isSafeInteger(twoPlaces)) {
|
||||
sp[i] = `${Math.round(twoPlaces)}rem`
|
||||
}
|
||||
else {
|
||||
sp[i] = `${parseFloat(twoPlaces).toFixed(2)}rem`
|
||||
}
|
||||
}
|
||||
|
||||
export default sp
|
||||
|
||||
@@ -9,6 +9,8 @@ import spacing from './spacing.tailwind'
|
||||
import { fontFamily, fontSize} from './fonts.tailwind'
|
||||
import typographyPlugin from './typo-plugin'
|
||||
|
||||
|
||||
|
||||
export default {
|
||||
presets: [],
|
||||
darkMode: ["class"],
|
||||
@@ -589,6 +591,7 @@ export default {
|
||||
fit: 'fit-content',
|
||||
},
|
||||
maxWidth: ({ theme, breakpoints }) => ({
|
||||
...spacing,
|
||||
none: 'none',
|
||||
0: '0rem',
|
||||
xs: '20rem',
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.js" // Conf files etc.
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import type { Breakpoint } from './breakpoints'
|
||||
|
||||
type Constraint = {
|
||||
w: number | `${number}%` | 'auto'
|
||||
h: number | `${number}%` | 'auto'
|
||||
}
|
||||
|
||||
/**
|
||||
* All values are in tw spacing units
|
||||
*
|
||||
*
|
||||
* NOTE: If applying in one dimension because other
|
||||
* is auto in style, ImageBlockComp applies this with style={}
|
||||
* so it has higher precidence than tw classes. Otherwise,
|
||||
* tw classes will be used.
|
||||
*/
|
||||
|
||||
type ResponsiveConstraints = {
|
||||
[key in (Breakpoint)]?: Constraint
|
||||
}
|
||||
|
||||
type Constraints = Constraint | ResponsiveConstraints
|
||||
|
||||
export {
|
||||
type Constraint,
|
||||
type ResponsiveConstraints,
|
||||
type Constraints
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { Constraints } from './constraints'
|
||||
import type { Dimensions } from './dimensions'
|
||||
|
||||
/**
|
||||
@@ -21,6 +22,9 @@ interface ImageDef {
|
||||
* can determine the aspect ratio
|
||||
*/
|
||||
dim: Dimensions
|
||||
|
||||
/** See Constraints */
|
||||
constraints?: Constraints
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -10,6 +10,7 @@ export { COMMON_GRID_2_COL, COMMON_GRID_3_COL } from './grid-def'
|
||||
export type {default as GridDef, GridColumnSpec} from './grid-def'
|
||||
export type { TShirtDimensions, Dimensions } from './dimensions'
|
||||
export type { ContactInfo, ContactInfoFields } from './contact-info'
|
||||
export type { Constraint, Constraints, ResponsiveConstraints } from './constraints'
|
||||
|
||||
import type BulletItem from './bullet-item'
|
||||
import type Icon from './icon'
|
||||
|
||||
@@ -2,7 +2,7 @@ import { compiler as mdCompiler } from 'markdown-to-jsx'
|
||||
|
||||
import { clsx, type ClassValue } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import type { Dimensions } from '../types'
|
||||
import type { Dimensions, Breakpoint, Constraints, Constraint, ResponsiveConstraints } from '../types'
|
||||
|
||||
// @ts-ignore
|
||||
import _merge from 'lodash.merge'
|
||||
@@ -51,6 +51,7 @@ export const asNum = (n: number | `${number}`): number => (
|
||||
)
|
||||
|
||||
// https://stackoverflow.com/questions/3971841/how-to-resize-images-proportionally-keeping-the-aspect-ratio
|
||||
/** deprecated */
|
||||
export const constrain = (dim: Dimensions, constraint: Dimensions): Dimensions => {
|
||||
const c = {
|
||||
w: asNum(constraint.w),
|
||||
@@ -68,6 +69,56 @@ export const constrain = (dim: Dimensions, constraint: Dimensions): Dimensions =
|
||||
}
|
||||
}
|
||||
|
||||
const _getConstraintClx = (con: Constraint, prefix?: string) => {
|
||||
|
||||
let clxArray: string[] = []
|
||||
if (typeof con.w === 'number') {
|
||||
clxArray.push(`max-w-${con.w}`)
|
||||
}
|
||||
else if (con.w === 'auto') {
|
||||
clxArray.push('max-w-auto')
|
||||
}
|
||||
else { // percentage
|
||||
clxArray.push(con.w === '100%' ? 'max-w-full' : `max-w-[${con.w as string}]`)
|
||||
}
|
||||
|
||||
if (typeof con.h === 'number') {
|
||||
clxArray.push(`max-h-${con.w}`)
|
||||
}
|
||||
else if (con.h === 'auto') {
|
||||
clxArray.push('max-h-auto')
|
||||
}
|
||||
else { // percentage
|
||||
|
||||
clxArray.push(con.h === '100%' ? 'max-w-full' : `max-h-[${con.h as string}]`)
|
||||
}
|
||||
|
||||
const _clxArray = (prefix) ? clxArray.map((t: string) => (prefix + t)) : clxArray
|
||||
return _clxArray.join(' ')
|
||||
}
|
||||
|
||||
export const getConstaintsClx = (
|
||||
con: Constraints | undefined,
|
||||
bp?: Breakpoint
|
||||
): string => {
|
||||
if (!con) return ''
|
||||
|
||||
// single value
|
||||
if ('w' in con) {
|
||||
return _getConstraintClx(con as Constraint)
|
||||
}
|
||||
if (bp && bp in con) {
|
||||
return _getConstraintClx(con[bp] as Constraint)
|
||||
}
|
||||
|
||||
let clxArray: string[] = []
|
||||
for (const [key, value] of Object.entries(con as ResponsiveConstraints)) {
|
||||
clxArray.push(_getConstraintClx(value, `${key}:`))
|
||||
}
|
||||
|
||||
return clxArray.join(' ')
|
||||
}
|
||||
|
||||
export const containsToken = (s: string | undefined, toFind: string): boolean => (s ? s.split(' ').includes(toFind) : false)
|
||||
|
||||
export const ldMerge = (
|
||||
|
||||
Reference in New Issue
Block a user