Merge branch 'tailwind-ts' into 'main'
Tailwind TypeScript See merge request soapbox-pub/soapbox!2889
This commit is contained in:
commit
1e0ff1e967
33 changed files with 124 additions and 118 deletions
|
@ -61,7 +61,7 @@ module.exports = {
|
|||
'URLSearchParams', // core-js
|
||||
],
|
||||
tailwindcss: {
|
||||
config: 'tailwind.config.cjs',
|
||||
config: 'tailwind.config.ts',
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -268,7 +268,7 @@ module.exports = {
|
|||
'error',
|
||||
{
|
||||
classRegex: '^(base|container|icon|item|list|outer|wrapper)?[c|C]lass(Name)?$',
|
||||
config: 'tailwind.config.cjs',
|
||||
config: 'tailwind.config.ts',
|
||||
},
|
||||
],
|
||||
'tailwindcss/migration-from-tailwind-2': 'error',
|
||||
|
|
|
@ -68,8 +68,8 @@
|
|||
"@soapbox.pub/wasmboy": "^0.8.0",
|
||||
"@tabler/icons": "^2.0.0",
|
||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@tanstack/react-query": "^5.0.0",
|
||||
"@types/escape-html": "^1.0.1",
|
||||
"@types/http-link-header": "^1.0.3",
|
||||
|
@ -209,7 +209,7 @@
|
|||
"rollup-plugin-visualizer": "^5.9.2",
|
||||
"stylelint": "^15.10.3",
|
||||
"stylelint-config-standard-scss": "^11.0.0",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"vite-plugin-checker": "^0.6.2",
|
||||
"vite-plugin-pwa": "^0.17.0",
|
||||
"vitest": "^0.34.4"
|
||||
|
|
|
@ -12,7 +12,7 @@ const BigCard: React.FC<IBigCard> = ({ title, subtitle, children }) => {
|
|||
return (
|
||||
<Card variant='rounded' size='xl'>
|
||||
<CardBody>
|
||||
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 dark:border-gray-800 sm:-mx-10 sm:pb-10'>
|
||||
<div className='-mx-4 mb-4 border-b border-solid border-gray-200 pb-4 sm:-mx-10 sm:pb-10 dark:border-gray-800'>
|
||||
<Stack space={2}>
|
||||
<Text size='2xl' align='center' weight='bold'>{title}</Text>
|
||||
{subtitle && <Text theme='muted' align='center'>{subtitle}</Text>}
|
||||
|
|
|
@ -28,7 +28,7 @@ const GdprBanner: React.FC = () => {
|
|||
|
||||
return (
|
||||
<Banner theme='opaque' className={clsx('transition-transform', { 'translate-y-full': slideout })}>
|
||||
<div className='flex flex-col space-y-4 rtl:space-x-reverse lg:flex-row lg:items-center lg:justify-between lg:space-x-4 lg:space-y-0'>
|
||||
<div className='flex flex-col space-y-4 lg:flex-row lg:items-center lg:justify-between lg:space-x-4 lg:space-y-0 rtl:space-x-reverse'>
|
||||
<Stack space={2}>
|
||||
<Text size='xl' weight='bold'>
|
||||
<FormattedMessage id='gdpr.title' defaultMessage='{siteTitle} uses cookies' values={{ siteTitle: instance.title }} />
|
||||
|
|
|
@ -84,7 +84,7 @@ const SiteErrorBoundary: React.FC<ISiteErrorBoundary> = ({ children }) => {
|
|||
|
||||
<div className='py-8'>
|
||||
<div className='mx-auto max-w-xl space-y-2 text-center'>
|
||||
<h1 className='text-3xl font-extrabold tracking-tight text-gray-900 dark:text-gray-500 sm:text-4xl'>
|
||||
<h1 className='text-3xl font-extrabold tracking-tight text-gray-900 sm:text-4xl dark:text-gray-500'>
|
||||
<FormattedMessage id='alert.unexpected.message' defaultMessage='Something went wrong.' />
|
||||
</h1>
|
||||
<p className='text-lg text-gray-700 dark:text-gray-600'>
|
||||
|
|
|
@ -13,7 +13,7 @@ const Select = React.forwardRef<HTMLSelectElement, ISelect>((props, ref) => {
|
|||
<select
|
||||
ref={ref}
|
||||
className={clsx(
|
||||
'w-full truncate rounded-md border-gray-300 py-2 pl-3 pr-10 text-base focus:border-primary-500 focus:outline-none focus:ring-primary-500 disabled:opacity-50 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:focus:border-primary-500 dark:focus:ring-primary-500 sm:text-sm',
|
||||
'w-full truncate rounded-md border-gray-300 py-2 pl-3 pr-10 text-base focus:border-primary-500 focus:outline-none focus:ring-primary-500 disabled:opacity-50 sm:text-sm dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:focus:border-primary-500 dark:focus:ring-primary-500',
|
||||
className,
|
||||
)}
|
||||
{...filteredProps}
|
||||
|
|
|
@ -45,7 +45,7 @@ const TagInput: React.FC<ITagInput> = ({ tags, onChange, placeholder }) => {
|
|||
return (
|
||||
<div className='relative mt-1 grow shadow-sm'>
|
||||
<HStack
|
||||
className='block w-full rounded-md border-gray-400 bg-white p-2 pb-0 text-gray-900 placeholder:text-gray-600 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus:border-primary-500 dark:focus:ring-primary-500 sm:text-sm'
|
||||
className='block w-full rounded-md border-gray-400 bg-white p-2 pb-0 text-gray-900 placeholder:text-gray-600 focus:border-primary-500 focus:ring-primary-500 sm:text-sm dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus:border-primary-500 dark:focus:ring-primary-500'
|
||||
space={2}
|
||||
wrap
|
||||
>
|
||||
|
|
|
@ -91,7 +91,7 @@ const Textarea = React.forwardRef(({
|
|||
ref={ref}
|
||||
rows={rows}
|
||||
onChange={handleChange}
|
||||
className={clsx('block w-full rounded-md text-gray-900 placeholder:text-gray-600 dark:text-gray-100 dark:placeholder:text-gray-600 sm:text-sm', {
|
||||
className={clsx('block w-full rounded-md text-gray-900 placeholder:text-gray-600 sm:text-sm dark:text-gray-100 dark:placeholder:text-gray-600', {
|
||||
'bg-white dark:bg-transparent shadow-sm border-gray-400 dark:border-gray-800 dark:ring-1 dark:ring-gray-800 focus:ring-primary-500 focus:border-primary-500 dark:focus:ring-primary-500 dark:focus:border-primary-500':
|
||||
theme === 'default',
|
||||
'bg-transparent border-0 focus:border-0 focus:ring-0': theme === 'transparent',
|
||||
|
|
|
@ -110,7 +110,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
return (
|
||||
<div className='-mx-4 -mt-4 sm:-mx-6 sm:-mt-6'>
|
||||
<div>
|
||||
<div className='relative h-32 w-full bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48' />
|
||||
<div className='relative h-32 w-full bg-gray-200 md:rounded-t-xl lg:h-48 dark:bg-gray-900/50' />
|
||||
</div>
|
||||
|
||||
<div className='px-4 sm:px-6'>
|
||||
|
@ -620,7 +620,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
)}
|
||||
|
||||
<div>
|
||||
<div className='relative isolate flex h-32 w-full flex-col justify-center overflow-hidden bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48'>
|
||||
<div className='relative isolate flex h-32 w-full flex-col justify-center overflow-hidden bg-gray-200 md:rounded-t-xl lg:h-48 dark:bg-gray-900/50'>
|
||||
{renderHeader()}
|
||||
|
||||
<div className='absolute left-2 top-2'>
|
||||
|
|
|
@ -44,7 +44,7 @@ const Search: React.FC = () => {
|
|||
<span style={{ display: 'none' }}>{intl.formatMessage(messages.search)}</span>
|
||||
|
||||
<input
|
||||
className='block w-full rounded-full focus:border-primary-500 focus:ring-primary-500 dark:bg-gray-800 dark:text-white dark:placeholder:text-gray-500 sm:text-sm'
|
||||
className='block w-full rounded-full focus:border-primary-500 focus:ring-primary-500 sm:text-sm dark:bg-gray-800 dark:text-white dark:placeholder:text-gray-500'
|
||||
type='text'
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
|
|
|
@ -16,7 +16,7 @@ const ConsumersList: React.FC<IConsumersList> = () => {
|
|||
|
||||
if (providers.length > 0) {
|
||||
return (
|
||||
<Card className='bg-gray-50 p-4 dark:bg-primary-800 sm:rounded-xl'>
|
||||
<Card className='bg-gray-50 p-4 sm:rounded-xl dark:bg-primary-800'>
|
||||
<Text size='xs' theme='muted'>
|
||||
<FormattedMessage id='oauth_consumers.title' defaultMessage='Other ways to sign in' />
|
||||
</Text>
|
||||
|
|
|
@ -60,7 +60,7 @@ const ChatPage: React.FC<IChatPage> = ({ chatId }) => {
|
|||
<div
|
||||
ref={containerRef}
|
||||
style={{ height }}
|
||||
className='h-screen overflow-hidden bg-white text-gray-900 shadow-lg dark:bg-primary-900 dark:text-gray-100 dark:shadow-none sm:rounded-t-xl'
|
||||
className='h-screen overflow-hidden bg-white text-gray-900 shadow-lg sm:rounded-t-xl dark:bg-primary-900 dark:text-gray-100 dark:shadow-none'
|
||||
>
|
||||
{isOnboarded ? (
|
||||
<div
|
||||
|
@ -68,7 +68,7 @@ const ChatPage: React.FC<IChatPage> = ({ chatId }) => {
|
|||
data-testid='chat-page'
|
||||
>
|
||||
<Stack
|
||||
className={clsx('dark:inset col-span-9 overflow-hidden bg-gradient-to-r from-white to-gray-100 dark:bg-gray-900 dark:bg-none sm:col-span-3', {
|
||||
className={clsx('dark:inset col-span-9 overflow-hidden bg-gradient-to-r from-white to-gray-100 sm:col-span-3 dark:bg-gray-900 dark:bg-none', {
|
||||
'hidden sm:block': isSidebarHidden,
|
||||
})}
|
||||
>
|
||||
|
|
|
@ -121,7 +121,7 @@ const ChatPageMain = () => {
|
|||
<HStack alignItems='center'>
|
||||
<IconButton
|
||||
src={require('@tabler/icons/arrow-left.svg')}
|
||||
className='mr-2 h-7 w-7 rtl:rotate-180 sm:mr-0 sm:hidden'
|
||||
className='mr-2 h-7 w-7 sm:mr-0 sm:hidden rtl:rotate-180'
|
||||
onClick={() => history.push('/chats')}
|
||||
/>
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ const ChatPageNew: React.FC<IChatPageNew> = () => {
|
|||
<HStack alignItems='center'>
|
||||
<IconButton
|
||||
src={require('@tabler/icons/arrow-left.svg')}
|
||||
className='mr-2 h-7 w-7 rtl:rotate-180 sm:mr-0 sm:hidden'
|
||||
className='mr-2 h-7 w-7 sm:mr-0 sm:hidden rtl:rotate-180'
|
||||
onClick={() => history.push('/chats')}
|
||||
/>
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ const ChatPageSettings = () => {
|
|||
<HStack alignItems='center'>
|
||||
<IconButton
|
||||
src={require('@tabler/icons/arrow-left.svg')}
|
||||
className='mr-2 h-7 w-7 rtl:rotate-180 sm:mr-0 sm:hidden'
|
||||
className='mr-2 h-7 w-7 sm:mr-0 sm:hidden rtl:rotate-180'
|
||||
onClick={() => history.push('/chats')}
|
||||
/>
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ const ChatTextarea: React.FC<IChatTextarea> = React.forwardRef(({
|
|||
bg-white text-gray-900
|
||||
shadow-sm placeholder:text-gray-600
|
||||
focus-within:border-primary-500
|
||||
focus-within:ring-1 focus-within:ring-primary-500 dark:border-gray-800 dark:bg-gray-800
|
||||
dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus-within:border-primary-500
|
||||
dark:focus-within:ring-primary-500 sm:text-sm
|
||||
focus-within:ring-1 focus-within:ring-primary-500 sm:text-sm dark:border-gray-800
|
||||
dark:bg-gray-800 dark:text-gray-100 dark:ring-1 dark:ring-gray-800 dark:placeholder:text-gray-600
|
||||
dark:focus-within:border-primary-500 dark:focus-within:ring-primary-500
|
||||
`}
|
||||
>
|
||||
{(!!attachments?.length || isUploading) && (
|
||||
|
|
|
@ -36,7 +36,7 @@ const HeaderPicker = React.forwardRef<HTMLInputElement, IMediaInput>(({ src, onC
|
|||
<label
|
||||
ref={picker}
|
||||
className={clsx(
|
||||
'dark:sm:shadow-inset relative h-24 w-full cursor-pointer overflow-hidden rounded-lg bg-primary-100 text-primary-500 dark:bg-gray-800 dark:text-accent-blue sm:h-36 sm:shadow',
|
||||
'dark:sm:shadow-inset relative h-24 w-full cursor-pointer overflow-hidden rounded-lg bg-primary-100 text-primary-500 sm:h-36 sm:shadow dark:bg-gray-800 dark:text-accent-blue',
|
||||
{
|
||||
'border-2 border-primary-600 border-dashed !z-[99]': isDragging,
|
||||
'ring-2 ring-offset-2 ring-primary-600': isDraggedOver,
|
||||
|
|
|
@ -80,7 +80,7 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
|||
return (
|
||||
<>
|
||||
<div className='-mx-4 -mt-4'>
|
||||
<div className='relative h-32 w-full bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48' />
|
||||
<div className='relative h-32 w-full bg-gray-200 md:rounded-t-xl lg:h-48 dark:bg-gray-900/50' />
|
||||
</div>
|
||||
|
||||
<PlaceholderEventHeader />
|
||||
|
@ -364,7 +364,7 @@ const EventHeader: React.FC<IEventHeader> = ({ status }) => {
|
|||
return (
|
||||
<>
|
||||
<div className='-mx-4 -mt-4'>
|
||||
<div className='relative h-32 w-full bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48'>
|
||||
<div className='relative h-32 w-full bg-gray-200 md:rounded-t-xl lg:h-48 dark:bg-gray-900/50'>
|
||||
{banner && (
|
||||
<a href={banner.url} onClick={handleHeaderClick} target='_blank'>
|
||||
<StillImage
|
||||
|
|
|
@ -24,7 +24,7 @@ const SuggestionItem: React.FC<ISuggestionItem> = ({ accountId }) => {
|
|||
if (!account) return null;
|
||||
|
||||
return (
|
||||
<Stack space={3} className='w-52 shrink-0 rounded-md border border-solid border-gray-300 p-4 dark:border-gray-800 md:w-full md:shrink md:border-transparent md:p-0 dark:md:border-transparent'>
|
||||
<Stack space={3} className='w-52 shrink-0 rounded-md border border-solid border-gray-300 p-4 md:w-full md:shrink md:border-transparent md:p-0 dark:border-gray-800 dark:md:border-transparent'>
|
||||
<Link
|
||||
to={`/@${account.acct}`}
|
||||
title={account.acct}
|
||||
|
|
|
@ -36,7 +36,7 @@ const GroupHeader: React.FC<IGroupHeader> = ({ group }) => {
|
|||
return (
|
||||
<div className='-mx-4 -mt-4 sm:-mx-6 sm:-mt-6' data-testid='group-header-missing'>
|
||||
<div>
|
||||
<div className='relative h-32 w-full bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48' />
|
||||
<div className='relative h-32 w-full bg-gray-200 md:rounded-t-xl lg:h-48 dark:bg-gray-900/50' />
|
||||
</div>
|
||||
|
||||
<div className='px-4 sm:px-6'>
|
||||
|
@ -92,7 +92,7 @@ const GroupHeader: React.FC<IGroupHeader> = ({ group }) => {
|
|||
<StillImage
|
||||
src={group.header}
|
||||
alt={intl.formatMessage(messages.header)}
|
||||
className='relative h-32 w-full bg-gray-200 object-center dark:bg-gray-900/50 md:rounded-t-xl lg:h-52'
|
||||
className='relative h-32 w-full bg-gray-200 object-center md:rounded-t-xl lg:h-52 dark:bg-gray-900/50'
|
||||
onError={() => setIsHeaderMissing(true)}
|
||||
/>
|
||||
);
|
||||
|
@ -109,7 +109,7 @@ const GroupHeader: React.FC<IGroupHeader> = ({ group }) => {
|
|||
return (
|
||||
<div
|
||||
data-testid='group-header-image'
|
||||
className='flex h-32 w-full items-center justify-center bg-gray-200 dark:bg-gray-800/30 md:rounded-t-xl lg:h-52'
|
||||
className='flex h-32 w-full items-center justify-center bg-gray-200 md:rounded-t-xl lg:h-52 dark:bg-gray-800/30'
|
||||
>
|
||||
{isHeaderMissing ? (
|
||||
<Icon src={require('@tabler/icons/photo-off.svg')} className='h-6 w-6 text-gray-500 dark:text-gray-700' />
|
||||
|
|
|
@ -26,7 +26,7 @@ const FediverseStep = ({ onNext }: { onNext: () => void }) => {
|
|||
</Text>
|
||||
|
||||
<Stack space={4}>
|
||||
<div className='border-b border-solid border-gray-200 pb-2 dark:border-gray-800 sm:pb-5'>
|
||||
<div className='border-b border-solid border-gray-200 pb-2 sm:pb-5 dark:border-gray-800'>
|
||||
<Stack space={4}>
|
||||
<Text theme='muted'>
|
||||
<FormattedMessage
|
||||
|
|
|
@ -8,7 +8,7 @@ import PlaceholderStatusContent from './placeholder-status-content';
|
|||
|
||||
/** Fake notification to display while data is loading. */
|
||||
const PlaceholderNotification = () => (
|
||||
<div className='bg-white px-4 py-6 dark:bg-primary-900 sm:p-6'>
|
||||
<div className='bg-white px-4 py-6 sm:p-6 dark:bg-primary-900'>
|
||||
<div className='w-full animate-pulse'>
|
||||
<div className='mb-2'>
|
||||
<PlaceholderStatusContent minLength={20} maxLength={20} />
|
||||
|
|
|
@ -209,7 +209,7 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
|
|||
<FormGroup
|
||||
labelText={<FormattedMessage id='compose_event.fields.banner_label' defaultMessage='Event banner' />}
|
||||
>
|
||||
<div className='dark:sm:shadow-inset relative flex h-24 items-center justify-center overflow-hidden rounded-lg bg-primary-100 text-primary-500 dark:bg-gray-800 dark:text-white sm:h-32 sm:shadow'>
|
||||
<div className='dark:sm:shadow-inset relative flex h-24 items-center justify-center overflow-hidden rounded-lg bg-primary-100 text-primary-500 sm:h-32 sm:shadow dark:bg-gray-800 dark:text-white'>
|
||||
{banner ? (
|
||||
<>
|
||||
<img className='h-full w-full object-cover' src={banner.url} alt='' />
|
||||
|
@ -234,7 +234,7 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
|
|||
labelText={<FormattedMessage id='compose_event.fields.description_label' defaultMessage='Event description' />}
|
||||
>
|
||||
<ComposeEditor
|
||||
className='block w-full rounded-md border border-gray-400 bg-white px-3 py-2 text-base text-gray-900 ring-1 placeholder:text-gray-600 focus-within:border-primary-500 focus-within:ring-primary-500 dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus-within:border-primary-500 dark:focus-within:ring-primary-500 sm:text-sm'
|
||||
className='block w-full rounded-md border border-gray-400 bg-white px-3 py-2 text-base text-gray-900 ring-1 placeholder:text-gray-600 focus-within:border-primary-500 focus-within:ring-primary-500 sm:text-sm dark:border-gray-800 dark:bg-gray-900 dark:text-gray-100 dark:ring-gray-800 dark:placeholder:text-gray-600 dark:focus-within:border-primary-500 dark:focus-within:ring-primary-500'
|
||||
placeholderClassName='pt-2'
|
||||
composeId='compose-event-modal'
|
||||
placeholder={intl.formatMessage(messages.eventDescriptionPlaceholder)}
|
||||
|
|
|
@ -42,7 +42,7 @@ const ConfirmationStep: React.FC<IConfirmationStep> = ({ group }) => {
|
|||
<Stack space={3}>
|
||||
<Stack>
|
||||
<label
|
||||
className='dark:sm:shadow-inset relative h-24 w-full cursor-pointer overflow-hidden rounded-lg bg-primary-100 text-primary-500 dark:bg-gray-800 dark:text-accent-blue sm:h-36 sm:shadow'
|
||||
className='dark:sm:shadow-inset relative h-24 w-full cursor-pointer overflow-hidden rounded-lg bg-primary-100 text-primary-500 sm:h-36 sm:shadow dark:bg-gray-800 dark:text-accent-blue'
|
||||
>
|
||||
{group.header && <img className='h-full w-full object-cover' src={group.header} alt='' />}
|
||||
</label>
|
||||
|
|
|
@ -76,7 +76,7 @@ const Navbar = () => {
|
|||
<div className='mx-auto max-w-7xl px-2 sm:px-6 lg:px-8'>
|
||||
<div className='relative flex h-12 justify-between lg:h-16'>
|
||||
{account && (
|
||||
<div className='absolute inset-y-0 left-0 flex items-center rtl:left-auto rtl:right-0 lg:hidden'>
|
||||
<div className='absolute inset-y-0 left-0 flex items-center lg:hidden rtl:left-auto rtl:right-0'>
|
||||
<button onClick={onOpenSidebar}>
|
||||
<Avatar src={account.avatar} size={34} />
|
||||
</button>
|
||||
|
@ -125,7 +125,7 @@ const Navbar = () => {
|
|||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<Form className='hidden items-center space-x-2 rtl:space-x-reverse xl:flex' onSubmit={handleSubmit}>
|
||||
<Form className='hidden items-center space-x-2 xl:flex rtl:space-x-reverse' onSubmit={handleSubmit}>
|
||||
<Input
|
||||
required
|
||||
value={username}
|
||||
|
|
|
@ -494,7 +494,7 @@ const UI: React.FC<IUI> = ({ children }) => {
|
|||
</Layout>
|
||||
|
||||
{(me && !shouldHideFAB()) && (
|
||||
<div className='fixed bottom-24 right-4 z-40 transition-all rtl:left-4 rtl:right-auto lg:hidden'>
|
||||
<div className='fixed bottom-24 right-4 z-40 transition-all lg:hidden rtl:left-4 rtl:right-auto'>
|
||||
<FloatingActionButton />
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -50,7 +50,7 @@ const HomePage: React.FC<IHomePage> = ({ children }) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Layout.Main className='space-y-3 pt-3 dark:divide-gray-800 sm:pt-0'>
|
||||
<Layout.Main className='space-y-3 pt-3 sm:pt-0 dark:divide-gray-800'>
|
||||
{me && (
|
||||
<Card
|
||||
className={clsx('relative z-[1] transition', {
|
||||
|
|
|
@ -20,7 +20,7 @@ const LandingPage: React.FC<ILandingPage> = ({ children }) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Layout.Main className='space-y-3 pt-3 dark:divide-gray-800 sm:pt-0'>
|
||||
<Layout.Main className='space-y-3 pt-3 sm:pt-0 dark:divide-gray-800'>
|
||||
{children}
|
||||
|
||||
{!me && (
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
const { parseColorMatrix } = require('./tailwind/colors.cjs');
|
||||
import aspectRatioPlugin from '@tailwindcss/aspect-ratio';
|
||||
import formsPlugin from '@tailwindcss/forms';
|
||||
import typographyPlugin from '@tailwindcss/typography';
|
||||
import { type Config } from 'tailwindcss';
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
import { parseColorMatrix } from './tailwind/colors';
|
||||
|
||||
const config: Config = {
|
||||
content: ['./src/**/*.{html,js,ts,tsx}', './custom/instance/**/*.html', './index.html'],
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
|
@ -98,8 +102,10 @@ module.exports = {
|
|||
},
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/forms'),
|
||||
require('@tailwindcss/typography'),
|
||||
require('@tailwindcss/aspect-ratio'),
|
||||
aspectRatioPlugin,
|
||||
formsPlugin,
|
||||
typographyPlugin,
|
||||
],
|
||||
};
|
||||
|
||||
export default config;
|
|
@ -1,46 +0,0 @@
|
|||
// https://tailwindcss.com/docs/customizing-colors#using-css-variables
|
||||
function withOpacityValue(variable) {
|
||||
return ({ opacityValue }) => {
|
||||
if (opacityValue === undefined) {
|
||||
return `rgb(var(${variable}))`;
|
||||
}
|
||||
return `rgb(var(${variable}) / ${opacityValue})`;
|
||||
};
|
||||
}
|
||||
|
||||
// Parse a single color as a CSS variable
|
||||
const toColorVariable = (colorName, tint = null) => {
|
||||
const suffix = tint ? `-${tint}` : '';
|
||||
const variable = `--color-${colorName}${suffix}`;
|
||||
|
||||
return withOpacityValue(variable);
|
||||
};
|
||||
|
||||
// Parse list of tints into Tailwind function with CSS variables
|
||||
const parseTints = (colorName, tints) => {
|
||||
return tints.reduce((colorObj, tint) => {
|
||||
colorObj[tint] = toColorVariable(colorName, tint);
|
||||
return colorObj;
|
||||
}, {});
|
||||
};
|
||||
|
||||
// Parse color matrix into Tailwind color palette
|
||||
const parseColorMatrix = colorMatrix => {
|
||||
return Object.entries(colorMatrix).reduce((palette, colorData) => {
|
||||
const [colorName, tints] = colorData;
|
||||
|
||||
// Conditionally parse array or single-tint colors
|
||||
if (Array.isArray(tints)) {
|
||||
palette[colorName] = parseTints(colorName, tints);
|
||||
} else if (tints === true) {
|
||||
palette[colorName] = toColorVariable(colorName);
|
||||
}
|
||||
|
||||
return palette;
|
||||
}, {});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
withOpacityValue,
|
||||
parseColorMatrix,
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
import {
|
||||
withOpacityValue,
|
||||
parseColorMatrix,
|
||||
} from './colors.cjs';
|
||||
} from './colors';
|
||||
|
||||
describe('withOpacityValue()', () => {
|
||||
it('returns a Tailwind color function with alpha support', () => {
|
||||
|
@ -11,8 +11,7 @@ describe('withOpacityValue()', () => {
|
|||
expect(typeof result).toBe('function');
|
||||
|
||||
// Test calling the function
|
||||
expect(result({})).toBe('rgb(var(--color-primary-500))');
|
||||
expect(result({ opacityValue: .5 })).toBe('rgb(var(--color-primary-500) / 0.5)');
|
||||
expect(result).toBe('rgb(var(--color-primary-500) / <alpha-value>)');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -29,8 +28,8 @@ describe('parseColorMatrix()', () => {
|
|||
const result = parseColorMatrix(colorMatrix);
|
||||
|
||||
// Colors are mapped to functions which return CSS values
|
||||
expect(result.primary[500]({})).toEqual('rgb(var(--color-primary-500))');
|
||||
expect(result.accent[300]({ opacityValue: .3 })).toEqual('rgb(var(--color-accent-300) / 0.3)');
|
||||
// @ts-ignore
|
||||
expect(result.accent['300']).toEqual('rgb(var(--color-accent-300) / <alpha-value>)');
|
||||
});
|
||||
|
||||
it('parses single-tint values', () => {
|
||||
|
@ -46,6 +45,6 @@ describe('parseColorMatrix()', () => {
|
|||
|
||||
const result = parseColorMatrix(colorMatrix);
|
||||
|
||||
expect(result['gradient-start']({ opacityValue: .7 })).toEqual('rgb(var(--color-gradient-start) / 0.7)');
|
||||
expect(result['gradient-start']).toEqual('rgb(var(--color-gradient-start) / <alpha-value>)');
|
||||
});
|
||||
});
|
47
tailwind/colors.ts
Normal file
47
tailwind/colors.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { type RecursiveKeyValuePair } from 'tailwindcss/types/config';
|
||||
|
||||
/** https://tailwindcss.com/docs/customizing-colors#using-css-variables */
|
||||
function withOpacityValue(variable: string): string {
|
||||
return `rgb(var(${variable}) / <alpha-value>)`;
|
||||
}
|
||||
|
||||
/** Parse a single color as a CSS variable. */
|
||||
const toColorVariable = (colorName: string, tint: number | null = null): string => {
|
||||
const suffix = tint ? `-${tint}` : '';
|
||||
const variable = `--color-${colorName}${suffix}`;
|
||||
|
||||
return withOpacityValue(variable);
|
||||
};
|
||||
|
||||
/** Parse list of tints into Tailwind function with CSS variables. */
|
||||
const parseTints = (colorName: string, tints: number[]): RecursiveKeyValuePair => {
|
||||
return tints.reduce<Record<string, string>>((colorObj, tint) => {
|
||||
colorObj[tint] = toColorVariable(colorName, tint);
|
||||
return colorObj;
|
||||
}, {});
|
||||
};
|
||||
|
||||
interface ColorMatrix {
|
||||
[colorName: string]: number[] | boolean;
|
||||
}
|
||||
|
||||
/** Parse color matrix into Tailwind color palette. */
|
||||
const parseColorMatrix = (colorMatrix: ColorMatrix): RecursiveKeyValuePair => {
|
||||
return Object.entries(colorMatrix).reduce<RecursiveKeyValuePair>((palette, colorData) => {
|
||||
const [colorName, tints] = colorData;
|
||||
|
||||
// Conditionally parse array or single-tint colors
|
||||
if (Array.isArray(tints)) {
|
||||
palette[colorName] = parseTints(colorName, tints);
|
||||
} else if (tints === true) {
|
||||
palette[colorName] = toColorVariable(colorName);
|
||||
}
|
||||
|
||||
return palette;
|
||||
}, {});
|
||||
};
|
||||
|
||||
export {
|
||||
withOpacityValue,
|
||||
parseColorMatrix,
|
||||
};
|
40
yarn.lock
40
yarn.lock
|
@ -2161,17 +2161,17 @@
|
|||
resolved "https://registry.yarnpkg.com/@tailwindcss/aspect-ratio/-/aspect-ratio-0.4.2.tgz#9ffd52fee8e3c8b20623ff0dcb29e5c21fb0a9ba"
|
||||
integrity sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==
|
||||
|
||||
"@tailwindcss/forms@^0.5.3":
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.3.tgz#e4d7989686cbcaf416c53f1523df5225332a86e7"
|
||||
integrity sha512-y5mb86JUoiUgBjY/o6FJSFZSEttfb3Q5gllE4xoKjAAD+vBrnIhE4dViwUuow3va8mpH4s9jyUbUbrRGoRdc2Q==
|
||||
"@tailwindcss/forms@^0.5.7":
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.7.tgz#db5421f062a757b5f828bc9286ba626c6685e821"
|
||||
integrity sha512-QE7X69iQI+ZXwldE+rzasvbJiyV/ju1FGHH0Qn2W3FKbuYtqp8LKcy6iSw79fVUT5/Vvf+0XgLCeYVG+UV6hOw==
|
||||
dependencies:
|
||||
mini-svg-data-uri "^1.2.3"
|
||||
|
||||
"@tailwindcss/typography@^0.5.9":
|
||||
version "0.5.9"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.9.tgz#027e4b0674929daaf7c921c900beee80dbad93e8"
|
||||
integrity sha512-t8Sg3DyynFysV9f4JDOVISGsjazNb48AeIYQwcL+Bsq5uf4RYL75C1giZ43KISjeDGBaTN3Kxh7Xj/vRSMJUUg==
|
||||
"@tailwindcss/typography@^0.5.10":
|
||||
version "0.5.10"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.10.tgz#2abde4c6d5c797ab49cf47610830a301de4c1e0a"
|
||||
integrity sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==
|
||||
dependencies:
|
||||
lodash.castarray "^4.4.0"
|
||||
lodash.isplainobject "^4.0.6"
|
||||
|
@ -4671,7 +4671,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
|||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||
|
||||
fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.5, fast-glob@^3.2.7, fast-glob@^3.2.9, fast-glob@^3.3.1:
|
||||
fast-glob@^3.2.11, fast-glob@^3.2.5, fast-glob@^3.2.7, fast-glob@^3.2.9, fast-glob@^3.3.1:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4"
|
||||
integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==
|
||||
|
@ -4682,7 +4682,7 @@ fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.5, fast-glob@^3.2.7, fast-g
|
|||
merge2 "^1.3.0"
|
||||
micromatch "^4.0.4"
|
||||
|
||||
fast-glob@^3.3.2:
|
||||
fast-glob@^3.3.0, fast-glob@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
|
||||
integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
|
||||
|
@ -5685,10 +5685,10 @@ jest-worker@^27.4.5:
|
|||
merge-stream "^2.0.0"
|
||||
supports-color "^8.0.0"
|
||||
|
||||
jiti@^1.18.2:
|
||||
version "1.20.0"
|
||||
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42"
|
||||
integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==
|
||||
jiti@^1.19.1:
|
||||
version "1.21.0"
|
||||
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d"
|
||||
integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==
|
||||
|
||||
js-base64@^3.6.0:
|
||||
version "3.7.5"
|
||||
|
@ -8433,20 +8433,20 @@ table@^6.8.1:
|
|||
string-width "^4.2.3"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
tailwindcss@^3.3.3:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf"
|
||||
integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==
|
||||
tailwindcss@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.0.tgz#045a9c474e6885ebd0436354e611a76af1c76839"
|
||||
integrity sha512-VigzymniH77knD1dryXbyxR+ePHihHociZbXnLZHUyzf2MMs2ZVqlUrZ3FvpXP8pno9JzmILt1sZPD19M3IxtA==
|
||||
dependencies:
|
||||
"@alloc/quick-lru" "^5.2.0"
|
||||
arg "^5.0.2"
|
||||
chokidar "^3.5.3"
|
||||
didyoumean "^1.2.2"
|
||||
dlv "^1.1.3"
|
||||
fast-glob "^3.2.12"
|
||||
fast-glob "^3.3.0"
|
||||
glob-parent "^6.0.2"
|
||||
is-glob "^4.0.3"
|
||||
jiti "^1.18.2"
|
||||
jiti "^1.19.1"
|
||||
lilconfig "^2.1.0"
|
||||
micromatch "^4.0.5"
|
||||
normalize-path "^3.0.0"
|
||||
|
|
Loading…
Reference in a new issue