Replace style props with tailwind classes (#800)

* add utility class for `word-break: break-word`

* refactor visuallyHidden style out of Page

* refactor out ref sizing hack in sidebar

* replace style props with tailwind classes
This commit is contained in:
Sinclair Chen 2022-08-26 14:23:06 -07:00 committed by GitHub
parent 3255806891
commit 8903b1ef95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 35 additions and 102 deletions

View File

@ -1,38 +0,0 @@
import clsx from 'clsx'
import { useState, ReactNode } from 'react'
export function AdvancedPanel(props: { children: ReactNode }) {
const { children } = props
const [collapsed, setCollapsed] = useState(true)
return (
<div
tabIndex={0}
className={clsx(
'collapse collapse-arrow relative',
collapsed ? 'collapse-close' : 'collapse-open'
)}
>
<div
onClick={() => setCollapsed((collapsed) => !collapsed)}
className="cursor-pointer"
>
<div className="mt-4 mr-6 text-right text-sm text-gray-500">
Advanced
</div>
<div
className="collapse-title absolute h-0 min-h-0 w-0 p-0"
style={{
top: -2,
right: -15,
color: '#6a7280' /* gray-500 */,
}}
/>
</div>
<div className="collapse-content m-0 !bg-transparent !p-0">
{children}
</div>
</div>
)
}

View File

@ -1,4 +1,5 @@
import { Point, ResponsiveLine } from '@nivo/line' import { Point, ResponsiveLine } from '@nivo/line'
import clsx from 'clsx'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { zip } from 'lodash' import { zip } from 'lodash'
import { useWindowSize } from 'web/hooks/use-window-size' import { useWindowSize } from 'web/hooks/use-window-size'
@ -26,8 +27,10 @@ export function DailyCountChart(props: {
return ( return (
<div <div
className="w-full overflow-hidden" className={clsx(
style={{ height: !small && (!width || width >= 800) ? 400 : 250 }} 'h-[250px] w-full overflow-hidden',
!small && 'md:h-[400px]'
)}
> >
<ResponsiveLine <ResponsiveLine
data={data} data={data}
@ -78,8 +81,10 @@ export function DailyPercentChart(props: {
return ( return (
<div <div
className="w-full overflow-hidden" className={clsx(
style={{ height: !small && (!width || width >= 800) ? 400 : 250 }} 'h-[250px] w-full overflow-hidden',
!small && 'md:h-[400px]'
)}
> >
<ResponsiveLine <ResponsiveLine
data={data} data={data}

View File

@ -108,10 +108,9 @@ export function ContractCard(props: {
/> />
<p <p
className={clsx( className={clsx(
'break-words font-semibold text-indigo-700 group-hover:underline group-hover:decoration-indigo-400 group-hover:decoration-2', 'break-anywhere font-semibold text-indigo-700 group-hover:underline group-hover:decoration-indigo-400 group-hover:decoration-2',
questionClass questionClass
)} )}
style={{ /* For iOS safari */ wordBreak: 'break-word' }}
> >
{question} {question}
</p> </p>

View File

@ -40,7 +40,7 @@ export function Leaderboard(props: {
{users.map((user, index) => ( {users.map((user, index) => (
<tr key={user.id}> <tr key={user.id}>
<td>{index + 1}</td> <td>{index + 1}</td>
<td style={{ maxWidth: 190 }}> <td className="max-w-[190px]">
<SiteLink className="relative" href={`/${user.username}`}> <SiteLink className="relative" href={`/${user.username}`}>
<Row className="items-center gap-4"> <Row className="items-center gap-4">
<Avatar avatarUrl={user.avatarUrl} size={8} /> <Avatar avatarUrl={user.avatarUrl} size={8} />

View File

@ -38,10 +38,7 @@ export function Linkify(props: { text: string; gray?: boolean }) {
) )
}) })
return ( return (
<span <span className="break-anywhere">
className="break-words"
style={{ /* For iOS safari */ wordBreak: 'break-word' }}
>
{text.split(regex).map((part, i) => ( {text.split(regex).map((part, i) => (
<Fragment key={i}> <Fragment key={i}>
{part} {part}

View File

@ -17,7 +17,7 @@ import { ManifoldLogo } from './manifold-logo'
import { MenuButton } from './menu' import { MenuButton } from './menu'
import { ProfileSummary } from './profile-menu' import { ProfileSummary } from './profile-menu'
import NotificationsIcon from 'web/components/notifications-icon' import NotificationsIcon from 'web/components/notifications-icon'
import React, { useState } from 'react' import React from 'react'
import { IS_PRIVATE_MANIFOLD } from 'common/envs/constants' import { IS_PRIVATE_MANIFOLD } from 'common/envs/constants'
import { CreateQuestionButton } from 'web/components/create-question-button' import { CreateQuestionButton } from 'web/components/create-question-button'
import { useMemberGroups } from 'web/hooks/use-group' import { useMemberGroups } from 'web/hooks/use-group'
@ -25,7 +25,6 @@ import { groupPath } from 'web/lib/firebase/groups'
import { trackCallback, withTracking } from 'web/lib/service/analytics' import { trackCallback, withTracking } from 'web/lib/service/analytics'
import { Group } from 'common/group' import { Group } from 'common/group'
import { Spacer } from '../layout/spacer' import { Spacer } from '../layout/spacer'
import { useWindowSize } from 'web/hooks/use-window-size'
import { CHALLENGES_ENABLED } from 'common/challenge' import { CHALLENGES_ENABLED } from 'common/challenge'
import { buildArray } from 'common/util/array' import { buildArray } from 'common/util/array'
import TrophyIcon from 'web/lib/icons/trophy-icon' import TrophyIcon from 'web/lib/icons/trophy-icon'
@ -235,19 +234,22 @@ export default function Sidebar(props: { className?: string }) {
})) }))
return ( return (
<nav aria-label="Sidebar" className={className}> <nav
aria-label="Sidebar"
className={clsx('flex max-h-[100vh] flex-col', className)}
>
<ManifoldLogo className="py-6" twoLine /> <ManifoldLogo className="py-6" twoLine />
<CreateQuestionButton user={user} /> <CreateQuestionButton user={user} />
<Spacer h={4} /> <Spacer h={4} />
{user && ( {user && (
<div className="w-full" style={{ minHeight: 80 }}> <div className="min-h-[80px] w-full">
<ProfileSummary user={user} /> <ProfileSummary user={user} />
</div> </div>
)} )}
{/* Mobile navigation */} {/* Mobile navigation */}
<div className="space-y-1 lg:hidden"> <div className="flex min-h-0 shrink flex-col gap-1 lg:hidden">
{mobileNavigationOptions.map((item) => ( {mobileNavigationOptions.map((item) => (
<SidebarItem key={item.href} item={item} currentPage={currentPage} /> <SidebarItem key={item.href} item={item} currentPage={currentPage} />
))} ))}
@ -266,7 +268,7 @@ export default function Sidebar(props: { className?: string }) {
</div> </div>
{/* Desktop navigation */} {/* Desktop navigation */}
<div className="hidden space-y-1 lg:block"> <div className="hidden min-h-0 shrink flex-col gap-1 lg:flex">
{navigationOptions.map((item) => ( {navigationOptions.map((item) => (
<SidebarItem key={item.href} item={item} currentPage={currentPage} /> <SidebarItem key={item.href} item={item} currentPage={currentPage} />
))} ))}
@ -286,10 +288,6 @@ export default function Sidebar(props: { className?: string }) {
function GroupsList(props: { currentPage: string; memberItems: Item[] }) { function GroupsList(props: { currentPage: string; memberItems: Item[] }) {
const { currentPage, memberItems } = props const { currentPage, memberItems } = props
const { height } = useWindowSize()
const [containerRef, setContainerRef] = useState<HTMLDivElement | null>(null)
const remainingHeight = (height ?? 0) - (containerRef?.offsetTop ?? 0)
// const preferredNotifications = useUnseenPreferredNotifications( // const preferredNotifications = useUnseenPreferredNotifications(
// privateUser, // privateUser,
// { // {
@ -315,11 +313,7 @@ function GroupsList(props: { currentPage: string; memberItems: Item[] }) {
currentPage={currentPage} currentPage={currentPage}
/> />
<div <div className="min-h-0 shrink space-y-0.5 overflow-auto">
className="flex-1 space-y-0.5 overflow-auto"
style={{ height: remainingHeight }}
ref={setContainerRef}
>
{memberItems.map((item) => ( {memberItems.map((item) => (
<a <a
href={item.href} href={item.href}

View File

@ -164,10 +164,7 @@ export function AnswerLabel(props: {
return ( return (
<Tooltip text={truncated === text ? false : text}> <Tooltip text={truncated === text ? false : text}>
<span <span className={clsx('break-anywhere whitespace-pre-line', className)}>
style={{ wordBreak: 'break-word' }}
className={clsx('whitespace-pre-line break-words', className)}
>
{truncated} {truncated}
</span> </span>
</Tooltip> </Tooltip>

View File

@ -6,13 +6,11 @@ import { Toaster } from 'react-hot-toast'
export function Page(props: { export function Page(props: {
rightSidebar?: ReactNode rightSidebar?: ReactNode
suspend?: boolean
className?: string className?: string
rightSidebarClassName?: string rightSidebarClassName?: string
children?: ReactNode children?: ReactNode
}) { }) {
const { children, rightSidebar, suspend, className, rightSidebarClassName } = const { children, rightSidebar, className, rightSidebarClassName } = props
props
const bottomBarPadding = 'pb-[58px] lg:pb-0 ' const bottomBarPadding = 'pb-[58px] lg:pb-0 '
return ( return (
@ -23,10 +21,9 @@ export function Page(props: {
bottomBarPadding, bottomBarPadding,
'mx-auto w-full lg:grid lg:grid-cols-12 lg:gap-x-2 xl:max-w-7xl xl:gap-x-8' 'mx-auto w-full lg:grid lg:grid-cols-12 lg:gap-x-2 xl:max-w-7xl xl:gap-x-8'
)} )}
style={suspend ? visuallyHiddenStyle : undefined}
> >
<Toaster /> <Toaster />
<Sidebar className="sticky top-0 hidden divide-gray-300 self-start pl-2 lg:col-span-2 lg:block" /> <Sidebar className="sticky top-0 hidden divide-gray-300 self-start pl-2 lg:col-span-2 lg:flex" />
<main <main
className={clsx( className={clsx(
'lg:col-span-8 lg:pt-6', 'lg:col-span-8 lg:pt-6',
@ -46,22 +43,7 @@ export function Page(props: {
</div> </div>
</aside> </aside>
</div> </div>
<BottomNavBar /> <BottomNavBar />
</> </>
) )
} }
const visuallyHiddenStyle = {
clip: 'rect(0 0 0 0)',
clipPath: 'inset(50%)',
height: 1,
margin: -1,
overflow: 'hidden',
padding: 0,
position: 'absolute',
width: 1,
whiteSpace: 'nowrap',
userSelect: 'none',
visibility: 'hidden',
} as const

View File

@ -3,7 +3,7 @@ import { ReactNode } from 'react'
import Link from 'next/link' import Link from 'next/link'
export const linkClass = export const linkClass =
'z-10 break-words hover:underline hover:decoration-indigo-400 hover:decoration-2' 'z-10 break-anywhere hover:underline hover:decoration-indigo-400 hover:decoration-2'
export const SiteLink = (props: { export const SiteLink = (props: {
href: string href: string
@ -19,7 +19,6 @@ export const SiteLink = (props: {
className={clsx(linkClass, className)} className={clsx(linkClass, className)}
href={href} href={href}
target={href.startsWith('http') ? '_blank' : undefined} target={href.startsWith('http') ? '_blank' : undefined}
style={{ /* For iOS safari */ wordBreak: 'break-word' }}
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
if (onClick) onClick() if (onClick) onClick()

View File

@ -148,10 +148,7 @@ export function UserPage(props: { user: User }) {
<Col className="mx-4 -mt-6"> <Col className="mx-4 -mt-6">
<Row className={'flex-wrap justify-between gap-y-2'}> <Row className={'flex-wrap justify-between gap-y-2'}>
<Col> <Col>
<span <span className="break-anywhere text-2xl font-bold">
className="text-2xl font-bold"
style={{ wordBreak: 'break-word' }}
>
{user.name} {user.name}
</span> </span>
<span className="text-gray-500">@{user.username}</span> <span className="text-gray-500">@{user.username}</span>

View File

@ -33,7 +33,7 @@ const Home = (props: { auth: { user: User } | null }) => {
return ( return (
<> <>
<Page suspend={!!contract}> <Page className={contract ? 'sr-only' : ''}>
<Col className="mx-auto w-full p-2"> <Col className="mx-auto w-full p-2">
<ContractSearch <ContractSearch
user={user} user={user}

View File

@ -203,8 +203,7 @@ function NewBidTable(props: {
<input <input
type="number" type="number"
placeholder="0" placeholder="0"
className="input input-bordered" className="input input-bordered max-w-[100px]"
style={{ maxWidth: 100 }}
value={newBid.toString()} value={newBid.toString()}
onChange={(e) => setNewBid(parseInt(e.target.value) || 0)} onChange={(e) => setNewBid(parseInt(e.target.value) || 0)}
onKeyUp={(e) => { onKeyUp={(e) => {
@ -292,7 +291,7 @@ export default function Simulator() {
YES YES
</div> </div>
</h1> </h1>
<div className="mb-10 w-full" style={{ height: 500 }}> <div className="mb-10 h-[500px] w-full">
<ResponsiveLine <ResponsiveLine
data={data} data={data}
yScale={{ min: 0, max: 100, type: 'linear' }} yScale={{ min: 0, max: 100, type: 'linear' }}

View File

@ -375,11 +375,10 @@ export function FirebaseAnalytics() {
</p> </p>
<Spacer h={4} /> <Spacer h={4} />
<iframe <iframe
className="w-full" className="w-full border-0"
height={2200} height={2200}
src="https://datastudio.google.com/embed/reporting/faeaf3a4-c8da-4275-b157-98dad017d305/page/Gg3" src="https://datastudio.google.com/embed/reporting/faeaf3a4-c8da-4275-b157-98dad017d305/page/Gg3"
frameBorder="0" frameBorder="0"
style={{ border: 0 }}
allowFullScreen allowFullScreen
/> />
</> </>
@ -400,11 +399,10 @@ export function WasabiCharts() {
</p> </p>
<Spacer h={4} /> <Spacer h={4} />
<iframe <iframe
className="w-full" className="w-full border-0"
height={21000} height={21000}
src="https://wasabipesto.com/jupyter/manifold/" src="https://wasabipesto.com/jupyter/manifold/"
frameBorder="0" frameBorder="0"
style={{ border: 0 }}
allowFullScreen allowFullScreen
/> />
</> </>

View File

@ -56,6 +56,10 @@ module.exports = {
display: 'none', display: 'none',
}, },
}, },
'.break-anywhere': {
'overflow-wrap': 'anywhere',
'word-break': 'break-word', // for Safari
},
}) })
}), }),
], ],