upgrade react-bootstrap

This commit is contained in:
keyan 2023-07-24 13:35:05 -05:00
parent 54d69489b9
commit 6407455def
89 changed files with 633 additions and 495 deletions

View File

@ -1,30 +1,30 @@
import { Accordion } from 'react-bootstrap'
import Accordion from 'react-bootstrap/Accordion'
import AccordionContext from 'react-bootstrap/AccordionContext'
import { useAccordionButton } from 'react-bootstrap/AccordionButton'
import ArrowRight from '../svgs/arrow-right-s-fill.svg'
import ArrowDown from '../svgs/arrow-down-s-fill.svg'
import { useEffect, useState } from 'react'
import { useContext } from 'react'
export default function AccordianItem ({ header, body, headerColor = 'var(--theme-grey)', show }) {
const [open, setOpen] = useState(show)
function ContextAwareToggle ({ children, headerColor = 'var(--theme-grey)', eventKey }) {
const { activeEventKey } = useContext(AccordionContext)
const decoratedOnClick = useAccordionButton(eventKey)
useEffect(() => {
setOpen(show)
}, [])
const isCurrentEventKey = activeEventKey === eventKey
return (
<Accordion
defaultActiveKey={show ? '0' : undefined}
>
<Accordion.Toggle
as={props => <div {...props} />}
eventKey='0'
style={{ cursor: 'pointer', display: 'flex', alignItems: 'center' }}
onClick={() => setOpen(!open)}
>
{open
? <ArrowDown style={{ fill: headerColor }} height={20} width={20} />
: <ArrowRight style={{ fill: headerColor }} height={20} width={20} />}
<div style={{ color: headerColor }}>{header}</div>
</Accordion.Toggle>
<div style={{ cursor: 'pointer', display: 'flex', alignItems: 'center' }} onClick={decoratedOnClick}>
{isCurrentEventKey
? <ArrowDown style={{ fill: headerColor }} height={20} width={20} />
: <ArrowRight style={{ fill: headerColor }} height={20} width={20} />}
{children}
</div>
)
}
export default function AccordianItem ({ header, body, headerColor = 'var(--theme-grey)', show }) {
return (
<Accordion defaultActiveKey={show ? '0' : undefined}>
<ContextAwareToggle eventKey='0'><div style={{ color: headerColor }}>{header}</div></ContextAwareToggle>
<Accordion.Collapse eventKey='0' className='mt-2'>
<div>{body}</div>
</Accordion.Collapse>

View File

@ -1,5 +1,6 @@
import { useFormikContext } from 'formik'
import { OverlayTrigger, Tooltip } from 'react-bootstrap'
import OverlayTrigger from 'react-bootstrap/OverlayTrigger'
import Tooltip from 'react-bootstrap/Tooltip'
export default function ActionTooltip ({ children, notForm, disable, overlayText, placement }) {
// if we're in a form, we want to hide tooltip on submit
@ -21,7 +22,9 @@ export default function ActionTooltip ({ children, notForm, disable, overlayText
trigger={['hover', 'focus']}
show={formik?.isSubmitting ? false : undefined}
>
{children}
<span>
{children}
</span>
</OverlayTrigger>
)
}

View File

@ -1,6 +1,6 @@
import AccordianItem from './accordian-item'
import { Input, InputUserSuggest } from './form'
import { InputGroup } from 'react-bootstrap'
import InputGroup from 'react-bootstrap/InputGroup'
import { BOOST_MIN } from '../lib/constants'
import Info from './info'
@ -21,7 +21,7 @@ export default function AdvPostForm ({ edit }) {
label={
<div className='d-flex align-items-center'>{edit ? 'add boost' : 'boost'}
<Info>
<ol className='font-weight-bold'>
<ol className='fw-bold'>
<li>Boost ranks posts higher temporarily based on the amount</li>
<li>The minimum boost is {BOOST_MIN} sats</li>
<li>Each {BOOST_MIN} sats of boost is equivalent to one trusted upvote

View File

@ -1,6 +1,7 @@
import { useRef, useState } from 'react'
import AvatarEditor from 'react-avatar-editor'
import { Button, Form as BootstrapForm } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import BootstrapForm from 'react-bootstrap/Form'
import Upload from './upload'
import EditImage from '../svgs/image-edit-fill.svg'
import Moon from '../svgs/moon-fill.svg'
@ -28,7 +29,7 @@ export default function Avatar ({ onSuccess }) {
<BootstrapForm.Control
type='range' onChange={e => setScale(parseFloat(e.target.value))}
min={1} max={2} step='0.05'
defaultValue={scale} custom
defaultValue={scale}
/>
</BootstrapForm.Group>
<Button onClick={() => {

View File

@ -1,6 +1,6 @@
import { useMutation } from '@apollo/client'
import { gql } from 'graphql-tag'
import { Dropdown } from 'react-bootstrap'
import Dropdown from 'react-bootstrap/Dropdown'
export default function BookmarkDropdownItem ({ item: { id, meBookmark } }) {
const [bookmarkItem] = useMutation(

View File

@ -4,7 +4,7 @@ import { gql, useApolloClient, useMutation } from '@apollo/client'
import Countdown from './countdown'
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
import FeeButton, { EditFeeButton } from './fee-button'
import { InputGroup } from 'react-bootstrap'
import InputGroup from 'react-bootstrap/InputGroup'
import { bountySchema } from '../lib/validate'
import { SubSelectInitial } from './sub-select-form'
import CancelButton from './cancel-button'
@ -95,7 +95,7 @@ export function BountyForm ({
topLevel
label={
<>
{textLabel} <small className='text-muted ml-2'>optional</small>
{textLabel} <small className='text-muted ms-2'>optional</small>
</>
}
name='text'
@ -103,7 +103,7 @@ export function BountyForm ({
hint={
editThreshold
? (
<div className='text-muted font-weight-bold'>
<div className='text-muted fw-bold'>
<Countdown date={editThreshold} />
</div>
)

View File

@ -1,9 +1,9 @@
import { useRouter } from 'next/router'
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
export default function CancelButton ({ onClick }) {
const router = useRouter()
return (
<Button className='mr-3 text-muted nav-link font-weight-bold' variant='link' onClick={onClick || (() => router.back())}>cancel</Button>
<Button className='me-3 text-muted nav-link fw-bold' variant='link' onClick={onClick || (() => router.back())}>cancel</Button>
)
}

View File

@ -2,7 +2,7 @@ import { Form, MarkdownInput, SubmitButton } from '../components/form'
import { gql, useMutation } from '@apollo/client'
import styles from './reply.module.css'
import { EditFeeButton } from './fee-button'
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import Delete from './delete'
import { commentSchema } from '../lib/validate'

View File

@ -18,7 +18,7 @@ import Flag from '../svgs/flag-fill.svg'
import { abbrNum } from '../lib/format'
import Share from './share'
import ItemInfo from './item-info'
import { Badge } from 'react-bootstrap'
import Badge from 'react-bootstrap/Badge'
import { RootProvider, useRoot } from './root'
import { useMe } from './me'
@ -43,7 +43,7 @@ function Parent ({ item, rootText }) {
</Link>
{root.subName &&
<Link href={`/~${root.subName}`}>
{' '}<Badge className={itemStyles.newComment} variant={null}>{root.subName}</Badge>
{' '}<Badge className={itemStyles.newComment} bg={null}>{root.subName}</Badge>
</Link>}
</>
)
@ -143,7 +143,7 @@ export default function Comment ({
pendingSats={pendingSats}
commentsText='replies'
className={`${itemStyles.other} ${styles.other}`}
embellishUser={op && <span className='text-boost font-weight-bold ml-1'>OP</span>}
embellishUser={op && <Badge bg='boost' className={`ms-1 ${styles.op} bg-opacity-75`}>OP</Badge>}
extraInfo={
<>
{includeParent && <Parent item={item} rootText={rootText} />}
@ -170,7 +170,7 @@ export default function Comment ({
}}
/>)}
{topLevel && (
<span className='d-flex ml-auto align-items-center'>
<span className='d-flex ms-auto align-items-center'>
<Share item={item} />
</span>
)}
@ -203,7 +203,7 @@ export default function Comment ({
{root.bounty && !bountyPaid && <PayBounty item={item} />}
</Reply>}
{children}
<div className={`${styles.comments} ml-sm-1 ml-md-3`}>
<div className={`${styles.comments} ms-sm-1 ms-md-3`}>
{item.comments && !noComments
? item.comments.map((item) => (
<Comment depth={depth + 1} key={item.id} item={item} />
@ -220,7 +220,7 @@ export default function Comment ({
function DepthLimit ({ item }) {
if (item.ncomments > 0) {
return (
<Link href={`/items/${item.id}`} className='d-block p-3 font-weight-bold text-muted w-100 text-center'>
<Link href={`/items/${item.id}`} className='d-block p-3 fw-bold text-muted w-100 text-center'>
view replies
</Link>
)
@ -252,7 +252,7 @@ export function CommentSkeleton ({ skeletonChildren }) {
<div className={styles.replyPadder}>
<div className={`${itemStyles.other} ${styles.reply} clouds`} />
</div>
<div className={`${styles.comments} ml-sm-1 ml-md-3`}>
<div className={`${styles.comments} ms-sm-1 ms-md-3`}>
{skeletonChildren
? <CommentSkeleton skeletonChildren={skeletonChildren - 1} />
: null}

View File

@ -26,6 +26,11 @@
cursor: pointer;
}
.op {
margin-top: -1px;
vertical-align: text-top;
}
.collapsed .hunk {
margin-bottom: .5rem;
}

View File

@ -2,7 +2,8 @@ import { gql, useApolloClient, useLazyQuery } from '@apollo/client'
import { useState } from 'react'
import Comment, { CommentSkeleton } from './comment'
import styles from './header.module.css'
import { Nav, Navbar } from 'react-bootstrap'
import Nav from 'react-bootstrap/Nav'
import Navbar from 'react-bootstrap/Navbar'
import { COMMENTS_QUERY } from '../fragments/items'
import { COMMENTS } from '../fragments/comments'
import { abbrNum } from '../lib/format'
@ -19,7 +20,7 @@ export function CommentsHeader ({ handleSort, pinned, bio, parentCreatedAt, comm
}
return (
<Navbar className='pt-1 pb-0'>
<Navbar className='pt-1 pb-0 px-3'>
<Nav
className={styles.navbarNav}
activeKey={sort}
@ -27,7 +28,7 @@ export function CommentsHeader ({ handleSort, pinned, bio, parentCreatedAt, comm
<Nav.Item className='text-muted'>
{abbrNum(commentSats)} sats
</Nav.Item>
<div className='ml-auto d-flex'>
<div className='ms-auto d-flex'>
<Nav.Item>
<Nav.Link
eventKey='hot'

View File

@ -1,7 +1,9 @@
import { Badge, OverlayTrigger, Tooltip } from 'react-bootstrap'
import Badge from 'react-bootstrap/Badge'
import OverlayTrigger from 'react-bootstrap/OverlayTrigger'
import Tooltip from 'react-bootstrap/Tooltip'
import CowboyHatIcon from '../svgs/cowboy.svg'
export default function CowboyHat ({ user, badge, className = 'ml-1', height = 16, width = 16 }) {
export default function CowboyHat ({ user, badge, className = 'ms-1', height = 16, width = 16 }) {
if (user?.streak === null || user.hideCowboyHat) {
return null
}
@ -11,11 +13,11 @@ export default function CowboyHat ({ user, badge, className = 'ml-1', height = 1
<HatTooltip overlayText={streak ? `${streak} days` : 'new'}>
{badge
? (
<Badge variant='grey-medium' className='ml-2 d-inline-flex align-items-center'>
<Badge bg='grey-medium' className='ms-2 d-inline-flex align-items-center'>
<CowboyHatIcon className={className} height={height} width={width} />
<span className='ml-1'>{streak || 'new'}</span>
<span className='ms-1 text-dark'>{streak || 'new'}</span>
</Badge>)
: <CowboyHatIcon className={className} height={height} width={width} />}
: <span><CowboyHatIcon className={className} height={height} width={width} /></span>}
</HatTooltip>
)
}

View File

@ -1,7 +1,9 @@
import { useMutation } from '@apollo/client'
import { gql } from 'graphql-tag'
import { useState } from 'react'
import { Alert, Button, Dropdown } from 'react-bootstrap'
import Alert from 'react-bootstrap/Alert'
import Button from 'react-bootstrap/Button'
import Dropdown from 'react-bootstrap/Dropdown'
import { useShowModal } from './modal'
export default function Delete ({ itemId, children, onDelete }) {
@ -63,7 +65,7 @@ function DeleteConfirm ({ onConfirm }) {
return (
<>
{error && <Alert variant='danger' onClose={() => setError(undefined)} dismissible>{error}</Alert>}
<p className='font-weight-bolder'>Are you sure? This is a gone forever kind of delete.</p>
<p className='fw-bolder'>Are you sure? This is a gone forever kind of delete.</p>
<div className='d-flex justify-content-end'>
<Button
variant='danger' onClick={async () => {

View File

@ -8,7 +8,7 @@ import { ITEM_FIELDS } from '../fragments/items'
import AccordianItem from './accordian-item'
import Item from './item'
import Delete from './delete'
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import { discussionSchema } from '../lib/validate'
import { SubSelectInitial } from './sub-select-form'
import CancelButton from './cancel-button'
@ -91,11 +91,11 @@ export function DiscussionForm ({
/>
<MarkdownInput
topLevel
label={<>{textLabel} <small className='text-muted ml-2'>optional</small></>}
label={<>{textLabel} <small className='text-muted ms-2'>optional</small></>}
name='text'
minRows={6}
hint={editThreshold
? <div className='text-muted font-weight-bold'><Countdown date={editThreshold} /></div>
? <div className='text-muted fw-bold'><Countdown date={editThreshold} /></div>
: null}
/>
<AdvPostForm edit={!!item} />

View File

@ -1,5 +1,5 @@
import { gql, useMutation } from '@apollo/client'
import { Dropdown } from 'react-bootstrap'
import Dropdown from 'react-bootstrap/Dropdown'
import FundError from './fund-error'
import { useShowModal } from './modal'

View File

@ -1,4 +1,4 @@
import { Table } from 'react-bootstrap'
import Table from 'react-bootstrap/Table'
import ActionTooltip from './action-tooltip'
import Info from './info'
import styles from './fee-button.module.css'
@ -31,7 +31,7 @@ function Receipt ({ cost, repetition, hasImgLink, baseFee, parentId, boost }) {
</tbody>
<tfoot>
<tr>
<td className='font-weight-bold'>{cost} sats</td>
<td className='fw-bold'>{cost} sats</td>
<td align='right' className='font-weight-light'>total fee</td>
</tr>
</tfoot>
@ -90,7 +90,7 @@ function EditReceipt ({ cost, paidSats, addImgLink, boost, parentId }) {
</tbody>
<tfoot>
<tr>
<td className='font-weight-bold'>{cost} sats</td>
<td className='fw-bold'>{cost} sats</td>
<td align='right' className='font-weight-light'>total fee</td>
</tr>
</tfoot>

View File

@ -1,4 +1,6 @@
import { Container, OverlayTrigger, Popover } from 'react-bootstrap'
import Container from 'react-bootstrap/Container'
import OverlayTrigger from 'react-bootstrap/OverlayTrigger'
import Popover from 'react-bootstrap/Popover'
import { CopyInput } from './form'
import styles from './footer.module.css'
import Texas from '../svgs/texas.svg'
@ -15,7 +17,7 @@ import useDarkMode from './dark-mode'
const RssPopover = (
<Popover>
<Popover.Content style={{ fontWeight: 500, fontSize: '.9rem' }}>
<Popover.Body style={{ fontWeight: 500, fontSize: '.9rem' }}>
<div className='d-flex justify-content-center'>
<a href='/rss' className='nav-link p-0 d-inline-flex'>
home
@ -38,13 +40,13 @@ const RssPopover = (
jobs
</a>
</div>
</Popover.Content>
</Popover.Body>
</Popover>
)
const SocialsPopover = (
<Popover>
<Popover.Content style={{ fontWeight: 500, fontSize: '.9rem' }}>
<Popover.Body style={{ fontWeight: 500, fontSize: '.9rem' }}>
<a
href='https://snort.social/p/npub1jfujw6llhq7wuvu5detycdsq5v5yqf56sgrdq8wlgrryx2a2p09svwm0gx' className='nav-link p-0 d-inline-flex'
target='_blank' rel='noreferrer'
@ -72,13 +74,13 @@ const SocialsPopover = (
>
pod
</a>
</Popover.Content>
</Popover.Body>
</Popover>
)
const ChatPopover = (
<Popover>
<Popover.Content style={{ fontWeight: 500, fontSize: '.9rem' }}>
<Popover.Body style={{ fontWeight: 500, fontSize: '.9rem' }}>
<a
href='https://tribes.sphinx.chat/t/stackerzchat' className='nav-link p-0 d-inline-flex'
target='_blank' rel='noreferrer'
@ -99,13 +101,13 @@ const ChatPopover = (
>
simplex
</a>
</Popover.Content>
</Popover.Body>
</Popover>
)
const AnalyticsPopover = (
<Popover>
<Popover.Content style={{ fontWeight: 500, fontSize: '.9rem' }}>
<Popover.Body style={{ fontWeight: 500, fontSize: '.9rem' }}>
<a
href='https://plausible.io/stacker.news' className='nav-link p-0 d-inline-flex'
target='_blank' rel='noreferrer'
@ -116,7 +118,7 @@ const AnalyticsPopover = (
<Link href='/stackers/day' className='nav-link p-0 d-inline-flex'>
stackers
</Link>
</Popover.Content>
</Popover.Body>
</Popover>
)
@ -151,7 +153,7 @@ export default function Footer ({ links = true }) {
<>
<div className='mb-1'>
<DarkModeIcon onClick={darkModeToggle} width={20} height={20} className='fill-grey theme' suppressHydrationWarning />
<LnIcon onClick={toggleLightning} width={20} height={20} className='ml-2 fill-grey theme' suppressHydrationWarning />
<LnIcon onClick={toggleLightning} width={20} height={20} className='ms-2 fill-grey theme' suppressHydrationWarning />
</div>
<div className='mb-0' style={{ fontWeight: 500 }}>
<Rewards />
@ -207,7 +209,7 @@ export default function Footer ({ links = true }) {
<div
className={`text-small mx-auto mb-2 ${styles.connect}`}
>
<span className='nav-item text-muted mr-2'>connect:</span>
<span className='nav-item text-muted me-2'>connect:</span>
<CopyInput
size='sm'
groupClassName='mb-0 w-100'
@ -219,23 +221,23 @@ export default function Footer ({ links = true }) {
href='https://amboss.space/node/03cc1d0932bb99b0697f5b5e5961b83ab7fd66f1efc4c9f5c7bad66c1bcbe78f02'
target='_blank' rel='noreferrer'
>
<Amboss className='ml-2 theme' width={20} height={20} />
<Amboss className='ms-2 theme' width={20} height={20} />
</a>
</div>}
<small className='d-flex justify-content-center align-items-center text-muted flex-wrap'>
<a className={`${styles.contrastLink} d-flex align-items-center`} href='https://github.com/stackernews/stacker.news' target='_blank' rel='noreferrer'>
FOSS <Github width={20} height={20} className='mx-1' />
</a>
made in Austin<Texas className='ml-1' width={20} height={20} />
<span className='ml-1'>by</span>
made in Austin<Texas className='ms-1' width={20} height={20} />
<span className='ms-1'>by</span>
<span>
<Link href='/k00b' className='ml-1'>
<Link href='/k00b' className='ms-1'>
@k00b
</Link>
<Link href='/kr' className='ml-1'>
<Link href='/kr' className='ms-1'>
@kr
</Link>
<Link href='/ekzyis' className='ml-1'>
<Link href='/ekzyis' className='ms-1'>
@ekzyis
</Link>
</span>

View File

@ -6,7 +6,10 @@ import { Formik, Form as FormikForm, useFormikContext, useField, FieldArray } fr
import React, { createContext, useContext, useEffect, useRef, useState } from 'react'
import copy from 'clipboard-copy'
import Thumb from '../svgs/thumb-up-fill.svg'
import { Col, Dropdown as BootstrapDropdown, Nav } from 'react-bootstrap'
import Col from 'react-bootstrap/Col'
import Dropdown from 'react-bootstrap/Dropdown'
import Nav from 'react-bootstrap/Nav'
import Row from 'react-bootstrap/Row'
import Markdown from '../svgs/markdown-line.svg'
import styles from './form.module.css'
import Text from '../components/text'
@ -53,6 +56,7 @@ export function CopyInput (props) {
onClick={handleClick}
append={
<Button
className={styles.appendButton}
size={props.size}
onClick={handleClick}
>
@ -109,7 +113,7 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, setH
<Nav.Link eventKey='preview' disabled={!meta.value}>preview</Nav.Link>
</Nav.Item>
<a
className='ml-auto text-muted d-flex align-items-center'
className='ms-auto text-muted d-flex align-items-center'
href='https://guides.github.com/features/mastering-markdown/' target='_blank' rel='noreferrer'
>
<Markdown width={18} height={18} />
@ -206,7 +210,7 @@ const insertMarkdownItalicFormatting = insertMarkdownFormatting(
function FormGroup ({ className, label, children }) {
return (
<BootstrapForm.Group className={className}>
<BootstrapForm.Group className={`form-group ${className}`}>
{label && <BootstrapForm.Label>{label}</BootstrapForm.Label>}
{children}
</BootstrapForm.Group>
@ -244,11 +248,7 @@ function InputInner ({
return (
<>
<InputGroup hasValidation>
{prepend && (
<InputGroup.Prepend>
{prepend}
</InputGroup.Prepend>
)}
{prepend}
<BootstrapForm.Control
onKeyDown={(e) => {
const metaOrCtrl = e.metaKey || e.ctrlKey
@ -274,26 +274,22 @@ function InputInner ({
isInvalid={invalid}
isValid={showValid && meta.initialValue !== meta.value && meta.touched && !meta.error}
/>
{(append || (clear && field.value)) && (
<InputGroup.Append>
{(clear && field.value) &&
<Button
variant={null}
onClick={(e) => {
helpers.setValue('')
if (storageKey) {
localStorage.removeItem(storageKey)
}
if (onChange) {
onChange(formik, { target: { value: '' } })
}
}}
className={`${styles.clearButton} ${invalid ? styles.isInvalid : ''}`}
><CloseIcon className='fill-grey' height={20} width={20} />
</Button>}
{append}
</InputGroup.Append>
)}
{(clear && field.value) &&
<Button
variant={null}
onClick={(e) => {
helpers.setValue('')
if (storageKey) {
localStorage.removeItem(storageKey)
}
if (onChange) {
onChange(formik, { target: { value: '' } })
}
}}
className={`${styles.clearButton} ${styles.appendButton} ${invalid ? styles.isInvalid : ''}`}
><CloseIcon className='fill-grey' height={20} width={20} />
</Button>}
{append}
<BootstrapForm.Control.Feedback type='invalid'>
{meta.touched && meta.error}
</BootstrapForm.Control.Feedback>
@ -357,10 +353,10 @@ export function InputUserSuggest ({ label, groupClassName, ...props }) {
}
}}
/>
<BootstrapDropdown show={suggestions.array.length > 0}>
<BootstrapDropdown.Menu className={styles.suggestionsMenu}>
<Dropdown show={suggestions.array.length > 0}>
<Dropdown.Menu className={styles.suggestionsMenu}>
{suggestions.array.map((v, i) =>
<BootstrapDropdown.Item
<Dropdown.Item
key={v.name}
active={suggestions.index === i}
onClick={() => {
@ -369,9 +365,9 @@ export function InputUserSuggest ({ label, groupClassName, ...props }) {
}}
>
{v.name}
</BootstrapDropdown.Item>)}
</BootstrapDropdown.Menu>
</BootstrapDropdown>
</Dropdown.Item>)}
</Dropdown.Menu>
</Dropdown>
</FormGroup>
)
}
@ -394,14 +390,14 @@ export function VariableInput ({ label, groupClassName, name, hint, max, min, re
<>
{options?.map((_, i) => (
<div key={i}>
<BootstrapForm.Row className='mb-2'>
<Row className='mb-2'>
<Col>
<InputInner name={`${name}[${i}]`} {...props} readOnly={i < readOnlyLen} placeholder={i >= min ? 'optional' : undefined} />
</Col>
{options.length - 1 === i && options.length !== max
? <AddIcon className='fill-grey align-self-center pointer mx-2' onClick={() => fieldArrayHelpers.push('')} />
? <Col className='d-flex ps-0' xs='auto'><AddIcon className='fill-grey align-self-center justify-self-center pointer' onClick={() => fieldArrayHelpers.push('')} /></Col>
: null}
</BootstrapForm.Row>
</Row>
</div>
))}
</>
@ -423,10 +419,9 @@ export function Checkbox ({ children, label, groupClassName, hiddenLabel, extra,
// return the correct bag of props for you
const [field,, helpers] = useField({ ...props, type: 'checkbox' })
return (
<BootstrapForm.Group className={groupClassName}>
<FormGroup className={groupClassName}>
{hiddenLabel && <BootstrapForm.Label className='invisible'>{label}</BootstrapForm.Label>}
<BootstrapForm.Check
custom
id={props.id || props.name}
inline={inline}
>
@ -444,7 +439,7 @@ export function Checkbox ({ children, label, groupClassName, hiddenLabel, extra,
</div>}
</BootstrapForm.Check.Label>
</BootstrapForm.Check>
</BootstrapForm.Group>
</FormGroup>
)
}
@ -497,8 +492,7 @@ export function Select ({ label, items, groupClassName, onChange, noForm, overri
return (
<FormGroup label={label} className={groupClassName}>
<BootstrapForm.Control
as='select'
<BootstrapForm.Select
{...field} {...props}
onChange={(e) => {
if (field?.onChange) {
@ -509,11 +503,10 @@ export function Select ({ label, items, groupClassName, onChange, noForm, overri
onChange(formik, e)
}
}}
custom
isInvalid={invalid}
>
{items.map(item => <option key={item}>{item}</option>)}
</BootstrapForm.Control>
</BootstrapForm.Select>
<BootstrapForm.Control.Feedback type='invalid'>
{meta.touched && meta.error}
</BootstrapForm.Control.Feedback>

View File

@ -19,15 +19,23 @@
height: auto;
}
.appendButton {
border-left: 0 !important;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.clearButton {
background-color: var(--theme-inputBg);
border: 1px solid var(--theme-borderColor);
padding: 0rem 0.5rem;
border-left: 0;
display: flex;
align-items: center;
}
.clearButton:hover, .clearButton:active {
background-color: var(--theme-inputBg) !important;
border: 1px solid var(--theme-borderColor) !important;
border-left: 0 !important;
}
.clearButton.isInvalid {
border-color: #c03221;
}

View File

@ -1,10 +1,10 @@
import Link from 'next/link'
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
export default function FundError ({ onClose }) {
return (
<>
<p className='font-weight-bolder'>you need more sats</p>
<p className='fw-bolder'>you need more sats</p>
<div className='d-flex justify-content-end'>
<Link href='/wallet?type=fund'>
<Button variant='success' onClick={onClose}>fund</Button>

View File

@ -3,7 +3,9 @@ import Nav from 'react-bootstrap/Nav'
import Link from 'next/link'
import styles from './header.module.css'
import { useRouter } from 'next/router'
import { Button, Container, NavDropdown } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import Container from 'react-bootstrap/Container'
import NavDropdown from 'react-bootstrap/NavDropdown'
import Price from './price'
import { useMe } from './me'
import Head from 'next/head'
@ -37,7 +39,7 @@ function Back () {
}, [router.asPath])
if (show) {
return <a role='button' tabIndex='0' className='nav-link standalone p-0' onClick={() => router.back()}><BackArrow className='theme mr-1 mr-md-2' width={22} height={22} /></a>
return <a role='button' tabIndex='0' className='nav-link standalone p-0' onClick={() => router.back()}><BackArrow className='theme me-1 me-md-2' width={22} height={22} /></a>
}
return null
}
@ -54,8 +56,8 @@ function NotificationBell () {
<link rel='shortcut icon' href={data?.hasNewNotes ? '/favicon-notify.png' : '/favicon.png'} />
</Head>
<Link href='/notifications' passHref legacyBehavior>
<Nav.Link eventKey='notifications' className='pl-0 position-relative'>
<NoteIcon height={22} width={22} className='theme' />
<Nav.Link eventKey='notifications' className='ps-0 position-relative'>
<NoteIcon height={22} width={22} className='theme' style={{ marginTop: '-4px' }} />
{data?.hasNewNotes &&
<span className={styles.notification}>
<span className='invisible'>{' '}</span>
@ -70,23 +72,23 @@ function StackerCorner ({ dropNavKey }) {
const me = useMe()
return (
<div className='d-flex align-items-center ml-auto'>
<div className='d-flex ms-auto'>
<NotificationBell />
<div className='position-relative'>
<NavDropdown
className={styles.dropdown}
title={
<Nav.Link eventKey={me.name} as='span' className='p-0 d-flex align-items-center' onClick={e => e.preventDefault()}>
<Nav.Link eventKey={me.name} as='span' className='p-0' onClick={e => e.preventDefault()}>
{`@${me.name}`}<CowboyHat user={me} />
</Nav.Link>
}
alignRight
align='end'
>
<Link href={'/' + me.name} passHref legacyBehavior>
<NavDropdown.Item active={me.name === dropNavKey}>
profile
{me && !me.bioId &&
<div className='p-1 d-inline-block bg-secondary ml-1'>
<div className='p-1 d-inline-block bg-secondary ms-1'>
<span className='invisible'>{' '}</span>
</div>}
</NavDropdown.Item>
@ -147,9 +149,9 @@ function LurkerCorner ({ path }) {
}), [router])
return path !== '/login' && path !== '/signup' && !path.startsWith('/invites') &&
<div className='ml-auto'>
<div className='ms-auto'>
<Button
className='align-items-center px-3 py-1 mr-2'
className='align-items-center px-3 py-1 me-2'
id='signup'
style={{ borderWidth: '2px' }}
variant='outline-grey-darkmode'
@ -158,7 +160,7 @@ function LurkerCorner ({ path }) {
login
</Button>
<Button
className='align-items-center pl-2 py-1 pr-3'
className='align-items-center ps-2 py-1 pe-3'
style={{ borderWidth: '2px' }}
id='login'
onClick={() => handleLogin('/signup')}
@ -166,7 +168,7 @@ function LurkerCorner ({ path }) {
<LightningIcon
width={17}
height={17}
className='mr-1'
className='me-1'
/>sign up
</Button>
</div>
@ -232,7 +234,7 @@ export default function Header ({ sub }) {
const me = useMe()
return (
<Container as='header' className='px-0'>
<Container as='header'>
<Navbar className='pb-0 pb-lg-2'>
<Nav
className={styles.navbarNav}
@ -249,11 +251,11 @@ export default function Header ({ sub }) {
<NavItems className='d-none d-lg-flex mx-2' prefix={prefix} sub={sub} />
<PostItem className='d-none d-lg-flex mx-2' prefix={prefix} />
<Link href={prefix + '/search'} passHref legacyBehavior>
<Nav.Link eventKey='search' className='position-relative d-none d-lg-flex align-items-center pr-0 ml-2'>
<Nav.Link eventKey='search' className='position-relative d-none d-lg-flex align-items-center pe-0 ms-2'>
<SearchIcon className='theme' width={22} height={22} />
</Nav.Link>
</Link>
<Nav.Item className={`${styles.price} ml-auto align-items-center ${me?.name.length > 10 ? 'd-none d-lg-flex' : ''}`}>
<Nav.Item className={`${styles.price} ms-auto align-items-center ${me?.name.length > 10 ? 'd-none d-lg-flex' : ''}`}>
<Price className='nav-link text-monospace' />
</Nav.Item>
{me ? <StackerCorner dropNavKey={dropNavKey} /> : <LurkerCorner path={path} />}
@ -264,13 +266,13 @@ export default function Header ({ sub }) {
className={`${styles.navbarNav}`}
activeKey={topNavKey}
>
<NavItems className='mr-1' prefix={prefix} sub={sub} />
<NavItems className='me-1' prefix={prefix} sub={sub} />
<Link href={prefix + '/search'} passHref legacyBehavior>
<Nav.Link eventKey='search' className='position-relative ml-auto d-flex mr-1'>
<Nav.Link eventKey='search' className='position-relative ms-auto d-flex me-1'>
<SearchIcon className='theme' width={22} height={22} />
</Nav.Link>
</Link>
<PostItem className='mr-0 pr-0' prefix={prefix} />
<PostItem className='me-0' prefix={prefix} />
</Nav>
</Navbar>
</Container>

View File

@ -5,7 +5,7 @@
line-height: 100%;
margin-bottom: -.3rem;
margin-right: 0;
text-shadow: 0 0 10px var(--primary);
text-shadow: 0 0 10px var(--bs-primary);
color: var(--theme-brandColor) !important;
}
@ -28,10 +28,14 @@
fill: var(--theme-navLinkActive);
}
.dropdown svg {
vertical-align: text-top;
}
.jobIndicator {
position: absolute;
padding: .25rem;
background-color: var(--primary);
background-color: var(--bs-primary);
top: 3px;
right: 0px;
border: 1px solid var(--theme-body);
@ -40,8 +44,8 @@
.notification {
position: absolute;
padding: .25rem;
background-color: var(--danger);
top: 3px;
background-color: var(--bs-danger);
top: 1px;
right: 8px;
border: 1px solid var(--theme-body);
}

View File

@ -6,7 +6,7 @@ export default function Info ({ children, iconClassName = 'fill-theme-color' })
return (
<InfoIcon
width={18} height={18} className={`${iconClassName} pointer ml-1`}
width={18} height={18} className={`${iconClassName} pointer ms-1`}
onClick={(e) => {
e.preventDefault()
showModal(onClose => children)

View File

@ -6,7 +6,7 @@ function InvoiceDefaultStatus ({ status }) {
return (
<div className='d-flex mt-2 justify-content-center'>
<Moon className='spin fill-grey' />
<div className='ml-3 text-muted' style={{ fontWeight: '600' }}>{status}</div>
<div className='ms-3 text-muted' style={{ fontWeight: '600' }}>{status}</div>
</div>
)
}
@ -15,7 +15,7 @@ function InvoiceConfirmedStatus ({ status }) {
return (
<div className='d-flex mt-2 justify-content-center'>
<Check className='fill-success' />
<div className='ml-3 text-success' style={{ fontWeight: '600' }}>{status}</div>
<div className='ms-3 text-success' style={{ fontWeight: '600' }}>{status}</div>
</div>
)
}
@ -24,7 +24,7 @@ function InvoiceFailedStatus ({ status }) {
return (
<div className='d-flex mt-2 justify-content-center'>
<ThumbDown className='fill-danger' />
<div className='ml-3 text-danger' style={{ fontWeight: '600' }}>{status}</div>
<div className='ms-3 text-danger' style={{ fontWeight: '600' }}>{status}</div>
</div>
)
}

View File

@ -1,4 +1,5 @@
import { Button, InputGroup } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import InputGroup from 'react-bootstrap/InputGroup'
import React, { useState, useRef, useEffect } from 'react'
import { Form, Input, SubmitButton } from './form'
import { useMe } from './me'
@ -12,12 +13,12 @@ const Tips = ({ setOValue }) => {
return tips.map(num =>
<Button
size='sm'
className={`${num > 1 ? 'ml-2' : ''} mb-2`}
className={`${num > 1 ? 'ms-2' : ''} mb-2`}
key={num}
onClick={() => { setOValue(num) }}
>
<UpBolt
className='mr-1'
className='me-1'
width={14}
height={14}
/>{num}
@ -77,7 +78,7 @@ export default function ItemAct ({ onClose, itemId, act, strike }) {
<Tips setOValue={setOValue} />
</div>
<div className='d-flex'>
<SubmitButton variant='success' className='ml-auto mt-1 px-4' value='TIP'>zap</SubmitButton>
<SubmitButton variant='success' className='ms-auto mt-1 px-4' value='TIP'>zap</SubmitButton>
</div>
</Form>
)

View File

@ -8,7 +8,7 @@ import styles from '../styles/item.module.css'
import itemStyles from './item.module.css'
import { NOFOLLOW_LIMIT } from '../lib/constants'
import { useMe } from './me'
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import { TwitterTweetEmbed } from 'react-twitter-embed'
import YouTube from 'react-youtube'
import useDarkMode from './dark-mode'
@ -134,7 +134,7 @@ function TopLevelItem ({ item, noReply, ...props }) {
{item.url && <ItemEmbed item={item} />}
{item.poll && <Poll item={item} />}
{item.bounty &&
<div className='font-weight-bold mt-2'>
<div className='fw-bold mt-2'>
{item.bountyPaidTo?.length
? (
<div className='px-3 py-1 d-inline-block bg-grey-medium rounded text-success'>

View File

@ -1,7 +1,8 @@
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { Badge, Dropdown } from 'react-bootstrap'
import Badge from 'react-bootstrap/Badge'
import Dropdown from 'react-bootstrap/Dropdown'
import Countdown from './countdown'
import { abbrNum } from '../lib/format'
import { newComments } from '../lib/new-comments'
@ -43,12 +44,12 @@ export default function ItemInfo ({ item, pendingSats, full, commentsText, class
</>}
<Link href={`/items/${item.id}`} title={`${item.commentSats} sats`} className='text-reset'>
{item.ncomments} {commentsText || 'comments'}
{hasNewComments && <>{' '}<Badge className={styles.newComment} variant={null}>new</Badge></>}
{hasNewComments && <>{' '}<Badge className={styles.newComment} bg={null}>new</Badge></>}
</Link>
<span> \ </span>
<span>
<Link href={`/${item.user.name}`} className='d-inline-flex align-items-center'>
@{item.user.name}<CowboyHat className='ml-1 fill-grey' user={item.user} height={12} width={12} />
<Link href={`/${item.user.name}`}>
@{item.user.name}<CowboyHat className='ms-1 fill-grey' user={item.user} height={12} width={12} />
{embellishUser}
</Link>
<span> </span>
@ -65,15 +66,15 @@ export default function ItemInfo ({ item, pendingSats, full, commentsText, class
</span>
{item.subName &&
<Link href={`/~${item.subName}`}>
{' '}<Badge className={styles.newComment} variant={null}>{item.subName}</Badge>
{' '}<Badge className={styles.newComment} bg={null}>{item.subName}</Badge>
</Link>}
{(item.outlawed && !item.mine &&
<Link href='/recent/outlawed'>
{' '}<Badge className={styles.newComment} variant={null}>outlawed</Badge>
{' '}<Badge className={styles.newComment} bg={null}>outlawed</Badge>
</Link>) ||
(item.freebie &&
<Link href='/recent/freebies'>
{' '}<Badge className={styles.newComment} variant={null}>freebie</Badge>
{' '}<Badge className={styles.newComment} bg={null}>freebie</Badge>
</Link>
)}
{canEdit && !item.deletedAt &&
@ -112,9 +113,9 @@ export default function ItemInfo ({ item, pendingSats, full, commentsText, class
export function ItemDropdown ({ children }) {
return (
<Dropdown className='pointer' as='span'>
<Dropdown.Toggle variant='success' id='dropdown-basic' as='a'>
<MoreIcon className='fill-grey ml-1' height={16} width={16} />
<Dropdown className={`pointer ${styles.dropdown}`} as='span'>
<Dropdown.Toggle variant='success' as='a'>
<MoreIcon className='fill-grey ms-1' height={16} width={16} />
</Dropdown.Toggle>
<Dropdown.Menu>
{children}

View File

@ -1,6 +1,8 @@
import * as Yup from 'yup'
import Toc from './table-of-contents'
import { Badge, Button, Image } from 'react-bootstrap'
import Badge from 'react-bootstrap/Badge'
import Button from 'react-bootstrap/Button'
import Image from 'react-bootstrap/Image'
import { SearchTitle } from './item'
import styles from './item.module.css'
import Link from 'next/link'
@ -28,7 +30,7 @@ export default function ItemJob ({ item, toc, rank, children }) {
</Link>
<div className={`${styles.hunk} align-self-center mb-0`}>
<div className={`${styles.main} flex-wrap d-inline`}>
<Link href={`/items/${item.id}`} className={`${styles.title} text-reset mr-2`}>
<Link href={`/items/${item.id}`} className={`${styles.title} text-reset me-2`}>
{item.searchTitle
? <SearchTitle title={item.searchTitle} />
: (
@ -49,7 +51,7 @@ export default function ItemJob ({ item, toc, rank, children }) {
<span> \ </span>
<span>
<Link href={`/${item.user.name}`} className='d-inline-flex align-items-center'>
@{item.user.name}<CowboyHat className='ml-1 fill-grey' user={item.user} height={12} width={12} />
@{item.user.name}<CowboyHat className='ms-1 fill-grey' user={item.user} height={12} width={12} />
</Link>
<span> </span>
<Link href={`/items/${item.id}`} title={item.createdAt} className='text-reset'>
@ -64,9 +66,9 @@ export default function ItemJob ({ item, toc, rank, children }) {
<Link href={`/items/${item.id}/edit`} className='text-reset'>
edit
</Link>
{item.status !== 'ACTIVE' && <span className='ml-1 font-weight-bold text-boost'> {item.status}</span>}
{item.status !== 'ACTIVE' && <span className='ms-1 fw-bold text-boost'> {item.status}</span>}
</>)}
{item.maxBid > 0 && item.status === 'ACTIVE' && <Badge className={`${styles.newComment} ml-1`}>PROMOTED</Badge>}
{item.maxBid > 0 && item.status === 'ACTIVE' && <Badge className={`${styles.newComment} ms-1`}>PROMOTED</Badge>}
</div>
</div>
{toc &&
@ -81,9 +83,9 @@ export default function ItemJob ({ item, toc, rank, children }) {
<Button
target='_blank' href={isEmail ? `mailto:${item.url}?subject=${encodeURIComponent(item.title)} via Stacker News` : item.url}
>
apply {isEmail && <EmailIcon className='ml-1' />}
apply {isEmail && <EmailIcon className='ms-1' />}
</Button>
{isEmail && <div className='ml-3 align-self-center text-muted font-weight-bold'>{item.url}</div>}
{isEmail && <div className='ms-3 align-self-center text-muted fw-bold'>{item.url}</div>}
</div>
{children}
</div>

View File

@ -39,22 +39,22 @@ export default function Item ({ item, rank, belowTitle, right, full, children, s
: item.meDontLike ? <Flag width={24} height={24} className={`${styles.dontLike}`} /> : <UpVote item={item} className={styles.upvote} pendingSats={pendingSats} setPendingSats={setPendingSats} />}
<div className={styles.hunk}>
<div className={`${styles.main} flex-wrap`}>
<Link href={`/items/${item.id}`} ref={titleRef} className={`${styles.title} text-reset mr-2`}>
<Link href={`/items/${item.id}`} ref={titleRef} className={`${styles.title} text-reset me-2`}>
{item.searchTitle ? <SearchTitle title={item.searchTitle} /> : item.title}
{item.pollCost && <span className={styles.icon}> <PollIcon className='fill-grey ml-1' height={14} width={14} /></span>}
{item.pollCost && <span className={styles.icon}> <PollIcon className='fill-grey ms-1' height={14} width={14} /></span>}
{item.bounty > 0 &&
<span className={styles.icon}>
<ActionTooltip notForm overlayText={`${abbrNum(item.bounty)} ${item.bountyPaidTo?.length ? 'sats paid' : 'sats bounty'}`}>
<BountyIcon className={`${styles.bountyIcon} ${item.bountyPaidTo?.length ? 'fill-success' : 'fill-grey'}`} height={16} width={16} />
</ActionTooltip>
</span>}
{image && <span className={styles.icon}><ImageIcon className='fill-grey ml-2' height={16} width={16} /></span>}
{image && <span className={styles.icon}><ImageIcon className='fill-grey ms-2' height={16} width={16} /></span>}
</Link>
{item.url && !image &&
<>
{/* eslint-disable-next-line */}
<a
className={`${styles.link} py-half py-md-0`} target='_blank' href={item.url}
className={`${styles.link}`} target='_blank' href={item.url}
rel={item.sats + item.boost >= NOFOLLOW_LIMIT ? null : 'nofollow'}
>
{item.url.replace(/(^https?:|^)\/\//, '')}
@ -88,7 +88,7 @@ export function ItemSkeleton ({ rank, children }) {
<UpVote className={styles.upvote} />
<div className={styles.hunk}>
<div className={`${styles.main} flex-wrap flex-md-nowrap`}>
<span className={`${styles.title} clouds text-reset flex-md-fill flex-md-shrink-0 mr-2`} />
<span className={`${styles.title} clouds text-reset flex-md-fill flex-md-shrink-0 me-2`} />
<span className={`${styles.link} clouds`} />
</div>
<div className={styles.other}>

View File

@ -4,6 +4,7 @@
max-width: 100%;
display: inline-block;
vertical-align: middle;
padding-bottom: .15rem;
}
.icon {
@ -24,12 +25,15 @@ a.title:visited {
overflow: hidden;
text-overflow: ellipsis;
flex: 1 0 128px;
padding-bottom: .15rem;
}
.newComment {
color: var(--theme-grey) !important;
background: var(--theme-clickToContextColor) !important;
vertical-align: middle;
margin-top: -1px;
margin-left: 0.1rem;
}
.pin {
@ -64,6 +68,16 @@ a.link:visited {
.other {
font-size: 80%;
color: var(--theme-grey);
vertical-align: text-top;
margin-bottom: .125rem;
}
.other svg {
vertical-align: text-top;
}
.other .dropdown svg {
margin-top: -1px;
}
.item {

View File

@ -1,5 +1,10 @@
import { Checkbox, Form, Input, MarkdownInput, SubmitButton } from './form'
import { InputGroup, Form as BForm, Col, Image } from 'react-bootstrap'
import Row from 'react-bootstrap/Row'
import Col from 'react-bootstrap/Col'
import InputGroup from 'react-bootstrap/InputGroup'
import Image from 'react-bootstrap/Image'
import BootstrapForm from 'react-bootstrap/Form'
import Alert from 'react-bootstrap/Alert'
import { useEffect, useState } from 'react'
import Info from './info'
import AccordianItem from './accordian-item'
@ -9,8 +14,6 @@ import { useRouter } from 'next/router'
import Link from 'next/link'
import { usePrice } from './price'
import Avatar from './avatar'
import BootstrapForm from 'react-bootstrap/Form'
import Alert from 'react-bootstrap/Alert'
import ActionTooltip from './action-tooltip'
import { jobSchema } from '../lib/validate'
import CancelButton from './cancel-button'
@ -115,7 +118,7 @@ export default function JobForm ({ item, sub }) {
required
clear
/>
<BForm.Row className='mr-0'>
<Row className='me-0'>
<Col>
<Input
label='location'
@ -124,10 +127,10 @@ export default function JobForm ({ item, sub }) {
/>
</Col>
<Checkbox
label={<div className='font-weight-bold'>remote</div>} name='remote' hiddenLabel
label={<div className='fw-bold'>remote</div>} name='remote' hiddenLabel
groupClassName={styles.inlineCheckGroup}
/>
</BForm.Row>
</Row>
<MarkdownInput
topLevel
label='description'
@ -136,7 +139,7 @@ export default function JobForm ({ item, sub }) {
required
/>
<Input
label={<>how to apply <small className='text-muted ml-2'>url or email address</small></>}
label={<>how to apply <small className='text-muted ms-2'>url or email address</small></>}
name='url'
required
clear
@ -187,14 +190,14 @@ function PromoteJob ({ item, sub, storageKeyPrefix }) {
label={
<div className='d-flex align-items-center'>bid
<Info>
<ol className='font-weight-bold'>
<ol className='fw-bold'>
<li>The higher your bid the higher your job will rank</li>
<li>You can increase, decrease, or remove your bid at anytime</li>
<li>You can edit or stop your job at anytime</li>
<li>If you run out of sats, your job will stop being promoted until you fill your wallet again</li>
</ol>
</Info>
<small className='text-muted ml-2'>optional</small>
<small className='text-muted ms-2'>optional</small>
</div>
}
name='maxBid'
@ -210,7 +213,7 @@ function PromoteJob ({ item, sub, storageKeyPrefix }) {
hint={<PriceHint monthly={monthly} />}
storageKeyPrefix={storageKeyPrefix}
/>
<><div className='font-weight-bold text-muted'>This bid puts your job in position: {position}</div></>
<><div className='fw-bold text-muted'>This bid puts your job in position: {position}</div></>
</>
}
/>
@ -227,10 +230,10 @@ function StatusControl ({ item }) {
<AccordianItem
header={<div style={{ fontWeight: 'bold', fontSize: '92%' }}>I want to stop my job</div>}
headerColor='var(--danger)'
headerColor='var(--bs-danger)'
body={
<Checkbox
label={<div className='font-weight-bold text-danger'>stop my job</div>} name='stop' inline
label={<div className='fw-bold text-danger'>stop my job</div>} name='stop' inline
/>
}
/>
@ -242,10 +245,10 @@ function StatusControl ({ item }) {
return (
<AccordianItem
header={<div style={{ fontWeight: 'bold', fontSize: '92%' }}>I want to resume my job</div>}
headerColor='var(--success)'
headerColor='var(--bs-success)'
body={
<Checkbox
label={<div className='font-weight-bold text-success'>resume my job</div>} name='start' inline
label={<div className='fw-bold text-success'>resume my job</div>} name='start' inline
/>
}
/>

View File

@ -1,7 +1,9 @@
import { gql, useMutation, useQuery } from '@apollo/client'
import { signIn } from 'next-auth/client'
import { useEffect } from 'react'
import { Col, Container, Row } from 'react-bootstrap'
import Col from 'react-bootstrap/Col'
import Container from 'react-bootstrap/Container'
import Row from 'react-bootstrap/Row'
import AccordianItem from './accordian-item'
import Qr, { QrSkeleton } from './qr'
import styles from './lightning-auth.module.css'
@ -37,9 +39,9 @@ function LightningExplainer ({ text, children }) {
<h3 className='w-100 pb-2'>
{text || 'Login'} with Lightning
</h3>
<div className='font-weight-bold text-muted pb-4'>This is the most private way to use Stacker News. Just open your Lightning wallet and scan the QR code.</div>
<div className='fw-bold text-muted pb-4'>This is the most private way to use Stacker News. Just open your Lightning wallet and scan the QR code.</div>
<Row className='w-100 text-muted'>
<Col className='pl-0 mb-4' md>
<Col className='ps-0 mb-4' md>
<AccordianItem
header={`Which wallets can I use to ${(text || 'Login').toLowerCase()}?`}
body={

View File

@ -9,7 +9,7 @@ import Item from './item'
import AccordianItem from './accordian-item'
import FeeButton, { EditFeeButton } from './fee-button'
import Delete from './delete'
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import { linkSchema } from '../lib/validate'
import Moon from '../svgs/moon-fill.svg'
import { SubSelectInitial } from './sub-select-form'
@ -143,7 +143,7 @@ export function LinkForm ({ item, sub, editThreshold, children }) {
autoComplete='off'
overrideValue={data?.pageTitleAndUnshorted?.unshorted}
hint={editThreshold
? <div className='text-muted font-weight-bold'><Countdown date={editThreshold} /></div>
? <div className='text-muted fw-bold'><Countdown date={editThreshold} /></div>
: null}
onChange={async (formik, e) => {
if ((/^ *$/).test(formik?.values.title)) {
@ -191,9 +191,9 @@ export function LinkForm ({ item, sub, editThreshold, children }) {
ChildButton={SubmitButton} variant='secondary'
/>
{dupesLoading &&
<div className='d-flex ml-3 justify-content-center'>
<div className='d-flex ms-3 justify-content-center'>
<Moon className='spin fill-grey' />
<div className='ml-2 text-muted' style={{ fontWeight: '600' }}>searching for dupes</div>
<div className='ms-2 text-muted' style={{ fontWeight: '600' }}>searching for dupes</div>
</div>}
</div>
)}

View File

@ -2,7 +2,7 @@ import GithubIcon from '../svgs/github-fill.svg'
import TwitterIcon from '../svgs/twitter-fill.svg'
import LightningIcon from '../svgs/bolt.svg'
import SlashtagsIcon from '../svgs/slashtags.svg'
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
export default function LoginButton ({ text, type, className, onClick }) {
let Icon, variant
@ -32,7 +32,7 @@ export default function LoginButton ({ text, type, className, onClick }) {
<Button className={className} variant={variant} onClick={onClick}>
<Icon
width={20}
height={20} className='mr-3'
height={20} className='me-3'
/>
{text} {name}
</Button>

View File

@ -71,7 +71,7 @@ export default function Login ({ providers, callbackUrl, error, text, Header, Fo
case 'Email':
return (
<div className='w-100' key={provider.name}>
<div className='mt-2 text-center text-muted font-weight-bold'>or</div>
<div className='mt-2 text-center text-muted fw-bold'>or</div>
<EmailLoginForm text={text} callbackUrl={callbackUrl} />
</div>
)

View File

@ -1,5 +1,5 @@
import { createContext, useCallback, useContext, useMemo, useState } from 'react'
import { Modal } from 'react-bootstrap'
import Modal from 'react-bootstrap/Modal'
export const ShowModalContext = createContext(() => null)

View File

@ -1,4 +1,4 @@
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import { useState } from 'react'
import Link from 'next/link'
@ -40,7 +40,7 @@ export function NavigateFooter ({ cursor, count, fetchMore, href, text, noMoreTe
let Footer
if (cursor) {
Footer = () => (
<Link href={href} className='text-reset text-muted font-weight-bold'>{text}</Link>
<Link href={href} className='text-reset text-muted fw-bold'>{text}</Link>
)
} else {
Footer = () => (

View File

@ -15,7 +15,7 @@ import { COMMENT_DEPTH_LIMIT } from '../lib/constants'
import CowboyHatIcon from '../svgs/cowboy.svg'
import BaldIcon from '../svgs/bald.svg'
import { RootProvider } from './root'
import { Alert } from 'react-bootstrap'
import Alert from 'react-bootstrap/Alert'
import styles from './notifications.module.css'
import { useServiceWorker } from './serviceworker'
import { Checkbox, Form } from './form'
@ -110,9 +110,9 @@ function Streak ({ n }) {
}
return (
<div className='d-flex font-weight-bold ml-2 py-1'>
<div className='d-flex fw-bold ms-2 py-1'>
<div style={{ fontSize: '2rem' }}>{n.days ? <BaldIcon className='fill-grey' height={40} width={40} /> : <CowboyHatIcon className='fill-grey' height={40} width={40} />}</div>
<div className='ml-1 p-1'>
<div className='ms-1 p-1'>
you {n.days ? 'lost your' : 'found a'} cowboy hat
<div><small style={{ lineHeight: '140%', display: 'inline-block' }}>{blurb(n)}</small></div>
</div>
@ -122,11 +122,11 @@ function Streak ({ n }) {
function EarnNotification ({ n }) {
return (
<div className='d-flex ml-2 py-1'>
<div className='d-flex ms-2 py-1'>
<HandCoin className='align-self-center fill-boost mx-1' width={24} height={24} style={{ flex: '0 0 24px', transform: 'rotateY(180deg)' }} />
<div className='ml-2'>
<div className='font-weight-bold text-boost'>
you stacked {n.earnedSats} sats in rewards<small className='text-muted ml-1'>{timeSince(new Date(n.sortTime))}</small>
<div className='ms-2'>
<div className='fw-bold text-boost'>
you stacked {n.earnedSats} sats in rewards<small className='text-muted ms-1'>{timeSince(new Date(n.sortTime))}</small>
</div>
{n.sources &&
<div style={{ fontSize: '80%', color: 'var(--theme-grey)' }}>
@ -146,10 +146,10 @@ function EarnNotification ({ n }) {
function Invitification ({ n }) {
return (
<NotificationLayout href='/invites'>
<small className='font-weight-bold text-secondary ml-2'>
<small className='fw-bold text-secondary ms-2'>
your invite has been redeemed by {n.invite.invitees.length} stackers
</small>
<div className='ml-4 mr-2 mt-1'>
<div className='ms-4 me-2 mt-1'>
<Invite
invite={n.invite} active={
!n.invite.revoked &&
@ -164,9 +164,9 @@ function Invitification ({ n }) {
function InvoicePaid ({ n }) {
return (
<NotificationLayout href={`/invoices/${n.invoice.id}`}>
<div className='font-weight-bold text-info ml-2 py-1'>
<Check className='fill-info mr-1' />{n.earnedSats} sats were deposited in your account
<small className='text-muted ml-1'>{timeSince(new Date(n.sortTime))}</small>
<div className='fw-bold text-info ms-2 py-1'>
<Check className='fill-info me-1' />{n.earnedSats} sats were deposited in your account
<small className='text-muted ms-1'>{timeSince(new Date(n.sortTime))}</small>
</div>
</NotificationLayout>
)
@ -175,9 +175,9 @@ function InvoicePaid ({ n }) {
function Referral ({ n }) {
return (
<NotificationLayout>
<small className='font-weight-bold text-secondary ml-2'>
<small className='fw-bold text-secondary ms-2'>
someone joined via one of your <Link href='/referrals/month' className='text-reset'>referral links</Link>
<small className='text-muted ml-1'>{timeSince(new Date(n.sortTime))}</small>
<small className='text-muted ms-1'>{timeSince(new Date(n.sortTime))}</small>
</small>
</NotificationLayout>
)
@ -186,7 +186,7 @@ function Referral ({ n }) {
function Votification ({ n }) {
return (
<NotificationLayout {...defaultOnClick(n)}>
<small className='font-weight-bold text-success ml-2'>
<small className='fw-bold text-success ms-2'>
your {n.item.title ? 'post' : 'reply'} {n.item.fwdUser ? 'forwarded' : 'stacked'} {n.earnedSats} sats{n.item.fwdUser && ` to @${n.item.fwdUser.name}`}
</small>
<div>
@ -207,7 +207,7 @@ function Votification ({ n }) {
function Mention ({ n }) {
return (
<NotificationLayout {...defaultOnClick(n)}>
<small className='font-weight-bold text-info ml-2'>
<small className='fw-bold text-info ms-2'>
you were mentioned in
</small>
<div>
@ -227,7 +227,7 @@ function Mention ({ n }) {
function JobChanged ({ n }) {
return (
<NotificationLayout {...defaultOnClick(n)}>
<small className={`font-weight-bold text-${n.item.status === 'ACTIVE' ? 'success' : 'boost'} ml-1`}>
<small className={`fw-bold text-${n.item.status === 'ACTIVE' ? 'success' : 'boost'} ms-1`}>
{n.item.status === 'ACTIVE'
? 'your job is active again'
: (n.item.status === 'NOSATS'
@ -306,7 +306,7 @@ function NotificationAlert () {
<Form className={`d-flex justify-content-end ${supported ? 'visible' : 'invisible'}`} initial={{ pushNotify: hasSubscription }}>
<Checkbox
name='pushNotify' label={<span className='text-muted'>push notifications</span>}
groupClassName={`${styles.subFormGroup} mb-1 mr-sm-3 mr-0`}
groupClassName={`${styles.subFormGroup} mb-1 me-sm-3 me-0`}
inline checked={hasSubscription} handleChange={async () => {
await sw.togglePushSubscription().catch(setError)
}}

View File

@ -14,7 +14,7 @@ export default function PastBounties ({ item }) {
return (
<AccordianItem
header={<div className='font-weight-bold'>{item.user.name}'s bounties</div>}
header={<div className='fw-bold'>{item.user.name}'s bounties</div>}
body={
<Items
variables={variables}

View File

@ -1,5 +1,5 @@
import React from 'react'
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import styles from './pay-bounty.module.css'
import ActionTooltip from './action-tooltip'
import { useMutation, gql } from '@apollo/client'
@ -96,7 +96,7 @@ export default function PayBounty ({ children, item }) {
className={styles.pay} onClick={() => {
showModal(onClose => (
<>
<div className='text-center font-weight-bold text-muted'>
<div className='text-center fw-bold text-muted'>
Pay this bounty to {item.user.name}?
</div>
<div className='text-center'>

View File

@ -1,4 +1,4 @@
.pay {
color: var(--success);
color: var(--bs-success);
margin-left: 1rem;
}

View File

@ -6,7 +6,7 @@ import AdvPostForm, { AdvPostInitial } from './adv-post-form'
import { MAX_POLL_NUM_CHOICES } from '../lib/constants'
import FeeButton, { EditFeeButton } from './fee-button'
import Delete from './delete'
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import { pollSchema } from '../lib/validate'
import { SubSelectInitial } from './sub-select-form'
import CancelButton from './cancel-button'
@ -71,7 +71,7 @@ export function PollForm ({ item, sub, editThreshold, children }) {
/>
<MarkdownInput
topLevel
label={<>text <small className='text-muted ml-2'>optional</small></>}
label={<>text <small className='text-muted ms-2'>optional</small></>}
name='text'
minRows={2}
/>
@ -82,7 +82,7 @@ export function PollForm ({ item, sub, editThreshold, children }) {
max={MAX_POLL_NUM_CHOICES}
min={2}
hint={editThreshold
? <div className='text-muted font-weight-bold'><Countdown date={editThreshold} /></div>
? <div className='text-muted fw-bold'><Countdown date={editThreshold} /></div>
: null}
/>
<AdvPostForm edit={!!item} />

View File

@ -1,5 +1,5 @@
import { gql, useMutation } from '@apollo/client'
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import { fixedDecimal } from '../lib/format'
import { timeLeft } from '../lib/time'
import { useMe } from './me'
@ -94,8 +94,8 @@ export default function Poll ({ item }) {
function PollResult ({ v, progress }) {
return (
<div className={styles.pollResult}>
<span className={styles.pollOption}>{v.option}{v.meVoted && <Check className='fill-grey ml-1 align-self-center' width={18} height={18} />}</span>
<span className='ml-auto mr-2 align-self-center'>{progress}%</span>
<span className={styles.pollOption}>{v.option}{v.meVoted && <Check className='fill-grey ms-1 align-self-center' width={18} height={18} />}</span>
<span className='ms-auto me-2 align-self-center'>{progress}%</span>
<div className={styles.pollProgress} style={{ width: `${progress}%` }} />
</div>
)

View File

@ -1,7 +1,7 @@
.pollButton {
margin-top: .25rem;
display: block;
border: 2px solid var(--info);
border: 2px solid var(--bs-info);
border-radius: 2rem;
width: 100%;
max-width: 600px;

View File

@ -1,6 +1,6 @@
import JobForm from './job-form'
import Link from 'next/link'
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import AccordianItem from './accordian-item'
import { useMe } from './me'
import { useRouter } from 'next/router'
@ -16,7 +16,7 @@ function FreebieDialog () {
<div className='text-center mb-4 text-muted'>
you have no sats, so this one is on us
<Info>
<ul className='font-weight-bold'>
<ul className='fw-bold'>
<li>Free posts have limited visibility and are hidden on the recent tab until other stackers zap them.</li>
<li>Free posts will not cover posts that cost more than 1 sat.</li>
<li>To get fully visibile and unrestricted posts right away, fund your account with a few sats or earn some on Stacker News.</li>
@ -39,20 +39,20 @@ export function PostForm ({ type, sub, children }) {
<Link href={prefix + '/post?type=link'}>
<Button variant='secondary'>link</Button>
</Link>
<span className='mx-3 font-weight-bold text-muted'>or</span>
<span className='mx-3 fw-bold text-muted'>or</span>
<Link href={prefix + '/post?type=discussion'}>
<Button variant='secondary'>discussion</Button>
</Link>
<div className='d-flex mt-4'>
<AccordianItem
headerColor='#6c757d'
header={<div className='font-weight-bold text-muted'>more types</div>}
header={<div className='fw-bold text-muted'>more types</div>}
body={
<div className='align-items-center'>
<Link href={prefix + '/post?type=poll'}>
<Button variant='info'>poll</Button>
</Link>
<span className='mx-3 font-weight-bold text-muted'>or</span>
<span className='mx-3 fw-bold text-muted'>or</span>
<Link href={prefix + '/post?type=bounty'}>
<Button variant='info'>bounty</Button>
</Link>

View File

@ -14,9 +14,9 @@ export default function RecentHeader ({ type, sub }) {
type: router.query.type || type || 'posts'
}}
>
<div className='text-muted font-weight-bold mt-0 mb-3 d-flex justify-content-end align-items-center'>
<div className='text-muted fw-bold mt-0 mb-3 d-flex justify-content-end align-items-center'>
<Select
groupClassName='mb-0 ml-2'
groupClassName='mb-0 ms-2'
className='w-auto'
name='type'
size='sm'

View File

@ -10,7 +10,7 @@ export default function Related ({ title, itemId }) {
return (
<AccordianItem
header={<div className='font-weight-bold'>related</div>}
header={<div className='fw-bold'>related</div>}
body={
<Items
query={RELATED_ITEMS}

View File

@ -23,7 +23,7 @@ function FreebieDialog () {
<div className='text-muted'>
you have no sats, so this one is on us
<Info>
<ul className='font-weight-bold'>
<ul className='fw-bold'>
<li>Free comments have limited visibility and are listed at the bottom of the comment section until other stackers zap them.</li>
<li>Free comments will not cover comments that cost more than 1 sat.</li>
<li>To get fully visibile and unrestricted comments right away, fund your account with a few sats or earn some on Stacker News.</li>

View File

@ -11,7 +11,7 @@
display: flex;
align-items: center;
cursor: pointer;
padding-bottom: .5rem;
padding: .25rem 0 .5rem 0;
line-height: 1rem;
vertical-align: middle;
}

View File

@ -1,4 +1,5 @@
import { Button, Container } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import Container from 'react-bootstrap/Container'
import styles from './search.module.css'
import SearchIcon from '../svgs/search-line.svg'
import CloseIcon from '../svgs/close-line.svg'
@ -57,7 +58,7 @@ export default function Search ({ sub }) {
return (
<>
<div className={`${styles.searchSection} ${showSearch ? styles.solid : styles.hidden}`}>
<Container className={`px-sm-0 ${styles.searchContainer} ${filter ? styles.leaveRoom : ''}`}>
<Container className={`px-md-0 ${styles.searchContainer} ${filter ? styles.leaveRoom : ''}`}>
{showSearch
? (
<Form
@ -71,9 +72,9 @@ export default function Search ({ sub }) {
onSubmit={search}
>
{filter &&
<div className='text-muted font-weight-bold my-3 d-flex align-items-center'>
<div className='text-muted fw-bold my-3 d-flex align-items-center'>
<Select
groupClassName='mr-2 mb-0'
groupClassName='me-2 mb-0'
onChange={(formik, e) => search({ ...formik?.values, what: e.target.value })}
name='what'
size='sm'
@ -91,7 +92,7 @@ export default function Search ({ sub }) {
/>
for
<Select
groupClassName='mb-0 ml-2'
groupClassName='mb-0 ms-2'
onChange={(formik, e) => search({ ...formik?.values, when: e.target.value })}
name='when'
size='sm'
@ -105,7 +106,7 @@ export default function Search ({ sub }) {
name='q'
required
autoFocus
groupClassName='mr-3 mb-0 flex-grow-1'
groupClassName='me-3 mb-0 flex-grow-1'
className='flex-grow-1'
clear
onChange={async (formik, e) => {

View File

@ -1,4 +1,4 @@
import { Dropdown } from 'react-bootstrap'
import Dropdown from 'react-bootstrap/Dropdown'
import ShareIcon from '../svgs/share-fill.svg'
import copy from 'clipboard-copy'
import { useMe } from './me'
@ -9,7 +9,7 @@ export default function Share ({ item }) {
return typeof window !== 'undefined' && navigator?.share
? (
<div className='ml-auto pointer d-flex align-items-center'>
<div className='ms-auto pointer d-flex align-items-center'>
<ShareIcon
width={20} height={20}
className='mx-2 fill-grey theme'
@ -28,7 +28,7 @@ export default function Share ({ item }) {
/>
</div>)
: (
<Dropdown alignRight className='ml-auto pointer d-flex align-items-center' as='span'>
<Dropdown align='end' className='ms-auto pointer d-flex align-items-center' as='span'>
<Dropdown.Toggle variant='success' id='dropdown-basic' as='a'>
<ShareIcon width={20} height={20} className='mx-2 fill-grey theme' />
</Dropdown.Toggle>

View File

@ -1,4 +1,4 @@
import { Alert } from 'react-bootstrap'
import Alert from 'react-bootstrap/Alert'
import YouTube from '../svgs/youtube-line.svg'
import { useEffect, useState } from 'react'
import { gql, useQuery } from '@apollo/client'
@ -24,7 +24,7 @@ export default function Snl ({ ignorePreference }) {
return (
<div className='d-flex'>
<Alert
variant='info' className='font-weight-bold mb-3 d-flex py-2 flex-shrink align-items-center'
variant='info' className='fw-bold mb-3 d-flex py-2 flex-shrink align-items-center'
onClose={() => {
setShow(undefined)
localStorage.setItem('snl', new Date())
@ -32,7 +32,7 @@ export default function Snl ({ ignorePreference }) {
dismissible
>
<a href='https://www.youtube.com/@stackernews/live'>
<YouTube width={24} height={24} className='mr-2 fill-info' />Stacker News Live is streaming this week's top stories
<YouTube width={24} height={24} className='me-2 fill-info' />Stacker News Live is streaming this week's top stories
</a>
</Alert>
</div>

View File

@ -18,7 +18,7 @@ export default function SubSelect ({ label, sub, setSub, item, ...props }) {
const SubInfo = () => (
<Info>
<div>
<div className='font-weight-bold'>The sub your post will go in ...</div>
<div className='fw-bold'>The sub your post will go in ...</div>
<ul>
<li>If it's bitcoin related, put it in the bitcoin sub.</li>
<li>If it's nostr related, put it in the nostr sub.</li>

View File

@ -1,6 +1,6 @@
import { useMutation } from '@apollo/client'
import { gql } from 'graphql-tag'
import { Dropdown } from 'react-bootstrap'
import Dropdown from 'react-bootstrap/Dropdown'
export default function SubscribeDropdownItem ({ item: { id, meSubscription } }) {
const [subscribeItem] = useMutation(

View File

@ -1,5 +1,6 @@
import React, { useMemo, useState } from 'react'
import { Dropdown, FormControl } from 'react-bootstrap'
import Dropdown from 'react-bootstrap/Dropdown'
import FormControl from 'react-bootstrap/FormControl'
import TocIcon from '../svgs/list-unordered.svg'
import { fromMarkdown } from 'mdast-util-from-markdown'
import { visit } from 'unist-util-visit'
@ -27,7 +28,7 @@ export default function Toc ({ text }) {
}
return (
<Dropdown alignRight className='d-flex align-items-center'>
<Dropdown align='end' className='d-flex align-items-center'>
<Dropdown.Toggle as={CustomToggle} id='dropdown-custom-components'>
<TocIcon width={20} height={20} className='mx-2 fill-grey theme' />
</Dropdown.Toggle>
@ -36,7 +37,7 @@ export default function Toc ({ text }) {
{toc.map(v => {
return (
<Dropdown.Item
className={v.depth === 1 ? 'font-weight-bold' : ''}
className={v.depth === 1 ? 'fw-bold' : ''}
style={{
marginLeft: `${(v.depth - 1) * 5}px`
}}

View File

@ -201,8 +201,8 @@ export function ZoomableImage ({ src, topLevel, ...props }) {
if (!src) return null
if (err) {
return (
<span className='d-flex align-items-center text-warning font-weight-bold pb-1'>
<FileMissing width={18} height={18} className='fill-warning mr-1' />
<span className='d-flex align-items-center text-warning fw-bold pb-1'>
<FileMissing width={18} height={18} className='fill-warning me-1' />
broken image <small>stacker probably used an unreliable host</small>
</span>
)

View File

@ -34,7 +34,7 @@ export default function TopHeader ({ sub, cat }) {
return (
<div className='d-flex'>
<Form
className='mr-auto'
className='me-auto'
initial={{
what: cat,
by: router.query.by || '',
@ -42,7 +42,7 @@ export default function TopHeader ({ sub, cat }) {
}}
onSubmit={top}
>
<div className='text-muted font-weight-bold my-3 d-flex align-items-center'>
<div className='text-muted fw-bold my-3 d-flex align-items-center'>
top
<Select
groupClassName='mx-2 mb-0'
@ -63,7 +63,7 @@ export default function TopHeader ({ sub, cat }) {
/>
for
<Select
groupClassName='mb-0 ml-2'
groupClassName='mb-0 ms-2'
onChange={(formik, e) => top({ ...formik?.values, when: e.target.value })}
name='when'
size='sm'

View File

@ -8,14 +8,15 @@ import { useMe } from './me'
import Rainbow from '../lib/rainbow'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import LongPressable from 'react-longpressable'
import { Overlay, Popover } from 'react-bootstrap'
import Overlay from 'react-bootstrap/Overlay'
import Popover from 'react-bootstrap/Popover'
import { useShowModal } from './modal'
import { useRouter } from 'next/router'
import { LightningConsumer } from './lightning'
const getColor = (meSats) => {
if (!meSats || meSats <= 10) {
return 'var(--secondary)'
return 'var(--bs-secondary)'
}
const idx = Math.min(
@ -33,13 +34,13 @@ const UpvotePopover = ({ target, show, handleClose }) => {
placement='right'
>
<Popover id='popover-basic'>
<Popover.Title className='d-flex justify-content-between alert-dismissible' as='h3'>Zapping
<Popover.Body className='d-flex justify-content-between alert-dismissible' as='h3'>Zapping
<button type='button' className='close' onClick={handleClose}><span aria-hidden='true'>×</span><span className='sr-only'>Close alert</span></button>
</Popover.Title>
<Popover.Content>
</Popover.Body>
<Popover.Body>
<div className='mb-2'>Press the bolt again to zap {me?.tipDefault || 1} more sat{me?.tipDefault > 1 ? 's' : ''}.</div>
<div>Repeatedly press the bolt to zap more sats.</div>
</Popover.Content>
</Popover.Body>
</Popover>
</Overlay>
)
@ -52,13 +53,13 @@ const TipPopover = ({ target, show, handleClose }) => (
placement='right'
>
<Popover id='popover-basic'>
<Popover.Title className='d-flex justify-content-between alert-dismissible' as='h3'>Press and hold
<Popover.Body className='d-flex justify-content-between alert-dismissible' as='h3'>Press and hold
<button type='button' className='close' onClick={handleClose}><span aria-hidden='true'>×</span><span className='sr-only'>Close alert</span></button>
</Popover.Title>
<Popover.Content>
</Popover.Body>
<Popover.Body>
<div className='mb-2'>Press and hold bolt to zap a custom amount.</div>
<div>As you zap more, the bolt color follows the rainbow.</div>
</Popover.Content>
</Popover.Body>
</Popover>
</Overlay>
)

View File

@ -11,10 +11,10 @@ export function UsageHeader () {
when: router.query.when || 'day'
}}
>
<div className='text-muted font-weight-bold my-3 d-flex align-items-center'>
<div className='text-muted fw-bold my-3 d-flex align-items-center'>
stacker analytics for
<Select
groupClassName='mb-0 ml-2'
groupClassName='mb-0 ms-2'
className='w-auto'
name='when'
size='sm'

View File

@ -1,4 +1,6 @@
import { Button, InputGroup, Image } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import InputGroup from 'react-bootstrap/InputGroup'
import Image from 'react-bootstrap/Image'
import Link from 'next/link'
import { useRouter } from 'next/router'
import Nav from 'react-bootstrap/Nav'
@ -158,23 +160,23 @@ function HeaderHeader ({ user }) {
const showModal = useShowModal()
const isMe = me?.name === user.name
const Satistics = () => <div className={`mb-2 ml-0 ml-sm-1 ${styles.username} text-success`}>{user.stacked} stacked</div>
const Satistics = () => <div className={`mb-2 ms-0 ms-sm-1 ${styles.username} text-success`}>{user.stacked} stacked</div>
const lnurlp = encodeLNUrl(new URL(`https://stacker.news/.well-known/lnurlp/${user.name}`))
return (
<div className='d-flex mt-2 flex-wrap flex-column flex-sm-row'>
<HeaderPhoto user={user} isMe={isMe} />
<div className='ml-0 ml-sm-3 mt-3 mt-sm-0 justify-content-center align-self-sm-center'>
<div className='ms-0 ms-sm-3 mt-3 mt-sm-0 justify-content-center align-self-sm-center'>
<HeaderNym user={user} isMe={isMe} />
<Satistics user={user} />
<Button
className='font-weight-bold ml-0' onClick={() => {
className='fw-bold ms-0' onClick={() => {
showModal(({ onClose }) => (
<>
<a className='d-flex m-auto p-3' style={{ background: 'white', width: 'fit-content' }} href={`lightning:${lnurlp}`}>
<QRCode className='d-flex m-auto' value={lnurlp} renderAs='svg' size={300} />
</a>
<div className='text-center font-weight-bold text-muted mt-3'>click or scan</div>
<div className='text-center fw-bold text-muted mt-3'>click or scan</div>
</>
))
}}
@ -182,12 +184,12 @@ function HeaderHeader ({ user }) {
<LightningIcon
width={20}
height={20}
className='mr-1'
className='me-1'
/>{user.name}@stacker.news
</Button>
<div className='d-flex flex-column mt-1 ml-0'>
<div className='d-flex flex-column mt-1 ms-0'>
<small className='text-muted d-flex-inline'>stacking since: {user.since
? <Link href={`/items/${user.since}`} className='ml-1'>#{user.since}</Link>
? <Link href={`/items/${user.since}`} className='ms-1'>#{user.since}</Link>
: <span>never</span>}
</small>
<small className='text-muted d-flex-inline'>longest cowboy streak: {user.maxStreak !== null ? user.maxStreak : 'none'}</small>

View File

@ -18,7 +18,7 @@
}
.nav :global .active {
border-bottom: 2px solid var(--primary);
border-bottom: 2px solid var(--bs-primary);
}
.userimg {

View File

@ -1,5 +1,5 @@
import Link from 'next/link'
import { Image } from 'react-bootstrap'
import Image from 'react-bootstrap/Image'
import { abbrNum } from '../lib/format'
import CowboyHat from './cowboy-hat'
import styles from './item.module.css'
@ -67,12 +67,12 @@ export default function UserList ({ ssrData, query, variables, destructureData }
<Link href={`/${user.name}`}>
<Image
src={user.photoId ? `https://${process.env.NEXT_PUBLIC_AWS_UPLOAD_BUCKET}.s3.amazonaws.com/${user.photoId}` : '/dorian400.jpg'} width='32' height='32'
className={`${userStyles.userimg} mr-2`}
className={`${userStyles.userimg} me-2`}
/>
</Link>
<div className={styles.hunk}>
<Link href={`/${user.name}`} className={`${styles.title} d-inline-flex align-items-center text-reset`}>
@{user.name}<CowboyHat className='ml-1 fill-grey' height={14} width={14} user={user} />
@{user.name}<CowboyHat className='ms-1 fill-grey' height={14} width={14} user={user} />
</Link>
<div className={styles.other}>
{statComps.map((Comp, i) => <Comp key={i} user={user} />)}
@ -94,7 +94,7 @@ export function UsersSkeleton () {
<Image
src={`${process.env.NEXT_PUBLIC_ASSET_PREFIX}/clouds.jpeg`}
width='32' height='32'
className={`${userStyles.userimg} clouds mr-2`}
className={`${userStyles.userimg} clouds me-2`}
/>
<div className={styles.hunk}>
<div className={`${styles.name} clouds text-reset`} />

View File

@ -42,12 +42,12 @@ const transformData = data => {
}
const COLORS = [
'var(--secondary)',
'var(--info)',
'var(--success)',
'var(--boost)',
'var(--bs-secondary)',
'var(--bs-info)',
'var(--bs-success)',
'var(--bs-boost)',
'var(--theme-grey)',
'var(--danger)'
'var(--bs-danger)'
]
export function WhenAreaChart ({ data }) {
@ -150,7 +150,7 @@ export function WhenComposedChart ({ data, lineNames, areaNames, barNames }) {
<Tooltip labelFormatter={dateFormatter(when)} contentStyle={{ color: 'var(--theme-color)', backgroundColor: 'var(--theme-body)' }} />
<Legend />
{barNames?.map((v, i) =>
<Bar yAxisId='right' key={v} type='monotone' dataKey={v} name={v} stroke='var(--info)' fill='var(--info)' />)}
<Bar yAxisId='right' key={v} type='monotone' dataKey={v} name={v} stroke='var(--bs-info)' fill='var(--bs-info)' />)}
{areaNames?.map((v, i) =>
<Area yAxisId='left' key={v} type='monotone' dataKey={v} name={v} stackId='1' stroke={COLORS[i]} fill={COLORS[i]} />)}
{lineNames?.map((v, i) =>

256
package-lock.json generated
View File

@ -23,7 +23,7 @@
"babel-plugin-inline-react-svg": "^2.0.1",
"bech32": "^2.0.0",
"bolt11": "^1.4.0",
"bootstrap": "^4.6.2",
"bootstrap": "^5.3.0",
"browserslist": "^4.21.4",
"canonical-json": "0.0.4",
"clipboard-copy": "^4.0.1",
@ -58,7 +58,7 @@
"qrcode.react": "^3.1.0",
"react": "^18.2.0",
"react-avatar-editor": "^13.0.0",
"react-bootstrap": "^1.6.6",
"react-bootstrap": "^2.8.0",
"react-countdown": "^2.3.3",
"react-dom": "^18.2.0",
"react-longpressable": "^1.1.1",
@ -2859,9 +2859,9 @@
}
},
"node_modules/@popperjs/core": {
"version": "2.11.6",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==",
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
@ -2952,6 +2952,17 @@
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
},
"node_modules/@react-aria/ssr": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.7.0.tgz",
"integrity": "sha512-bfufjg4ESE5giN+Fxj1XIzS5f/YIhqcGc+Ve+vUUKU8xZ8t/Xtjlv8F3kjqDBQdk//n3mluFY7xG1wQVB9rMLQ==",
"dependencies": {
"@swc/helpers": "^0.5.0"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
}
},
"node_modules/@remusao/guess-url-type": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@remusao/guess-url-type/-/guess-url-type-1.2.1.tgz",
@ -2989,25 +3000,45 @@
"resolved": "https://registry.npmjs.org/@remusao/trie/-/trie-1.4.1.tgz",
"integrity": "sha512-yvwa+aCyYI/UjeD39BnpMypG8N06l86wIDW1/PAc6ihBRnodIfZDwccxQN3n1t74wduzaz74m4ZMHZnB06567Q=="
},
"node_modules/@restart/context": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz",
"integrity": "sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q==",
"peerDependencies": {
"react": ">=16.3.2"
}
},
"node_modules/@restart/hooks": {
"version": "0.4.7",
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.7.tgz",
"integrity": "sha512-ZbjlEHcG+FQtpDPHd7i4FzNNvJf2enAwZfJbpM8CW7BhmOAbsHpZe3tsHwfQUrBuyrxWqPYp2x5UMnilWcY22A==",
"version": "0.4.11",
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.11.tgz",
"integrity": "sha512-Ft/ncTULZN6ldGHiF/k5qt72O8JyRMOeg0tApvCni8LkoiEahO+z3TNxfXIVGy890YtWVDvJAl662dVJSJXvMw==",
"dependencies": {
"dequal": "^2.0.2"
"dequal": "^2.0.3"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@restart/ui": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.6.tgz",
"integrity": "sha512-eC3puKuWE1SRYbojWHXnvCNHGgf3uzHCb6JOhnF4OXPibOIPEkR1sqDSkL643ydigxwh+ruCa1CmYHlzk7ikKA==",
"dependencies": {
"@babel/runtime": "^7.21.0",
"@popperjs/core": "^2.11.6",
"@react-aria/ssr": "^3.5.0",
"@restart/hooks": "^0.4.9",
"@types/warning": "^3.0.0",
"dequal": "^2.0.3",
"dom-helpers": "^5.2.0",
"uncontrollable": "^8.0.1",
"warning": "^4.0.3"
},
"peerDependencies": {
"react": ">=16.14.0",
"react-dom": ">=16.14.0"
}
},
"node_modules/@restart/ui/node_modules/uncontrollable": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.2.tgz",
"integrity": "sha512-/GDx+K1STGtpgTsj5Dj3J51YaKxZDblbCQHTH1zHLuoBEWodj6MjtRVv3TUijj1JYLRLSFsFzN8NV4M3QV4d9w==",
"peerDependencies": {
"react": ">=16.14.0"
}
},
"node_modules/@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@ -3475,11 +3506,6 @@
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz",
"integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ=="
},
"node_modules/@types/invariant": {
"version": "2.2.35",
"resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.35.tgz",
"integrity": "sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg=="
},
"node_modules/@types/json-schema": {
"version": "7.0.12",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
@ -4903,9 +4929,9 @@
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"node_modules/bootstrap": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz",
"integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==",
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.0.tgz",
"integrity": "sha512-UnBV3E3v4STVNQdms6jSGO2CvOkjUMdDAVR2V5N4uCMdaIkaQjbcEAMqRimDHIs4uqBYzDAKCQwCB+97tJgHQw==",
"funding": [
{
"type": "github",
@ -4917,8 +4943,7 @@
}
],
"peerDependencies": {
"jquery": "1.9.1 - 3",
"popper.js": "^1.16.1"
"@popperjs/core": "^2.11.7"
}
},
"node_modules/bplist-parser": {
@ -14227,31 +14252,42 @@
}
},
"node_modules/react-bootstrap": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.6.6.tgz",
"integrity": "sha512-pSzYyJT5u4rc8+5myM8Vid2JG52L8AmYSkpznReH/GM4+FhLqEnxUa0+6HRTaGwjdEixQNGchwY+b3xCdYWrDA==",
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.8.0.tgz",
"integrity": "sha512-e/aNtxl0Z2ozrIaR82jr6Zz7ss9GSoaXpQaxmvtDUsTZIq/XalkduR/ZXP6vbQHz2T4syvjA+4FbtwELxxmpww==",
"dependencies": {
"@babel/runtime": "^7.14.0",
"@restart/context": "^2.1.4",
"@restart/hooks": "^0.4.7",
"@types/invariant": "^2.2.33",
"@types/prop-types": "^15.7.3",
"@types/react": ">=16.14.8",
"@types/react-transition-group": "^4.4.1",
"@types/warning": "^3.0.0",
"classnames": "^2.3.1",
"@babel/runtime": "^7.21.0",
"@restart/hooks": "^0.4.9",
"@restart/ui": "^1.6.3",
"@types/react-transition-group": "^4.4.5",
"classnames": "^2.3.2",
"dom-helpers": "^5.2.1",
"invariant": "^2.2.4",
"prop-types": "^15.7.2",
"prop-types": "^15.8.1",
"prop-types-extra": "^1.1.0",
"react-overlays": "^5.1.2",
"react-transition-group": "^4.4.1",
"react-transition-group": "^4.4.5",
"uncontrollable": "^7.2.1",
"warning": "^4.0.3"
},
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
"@types/react": ">=16.14.8",
"react": ">=16.14.0",
"react-dom": ">=16.14.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/react-bootstrap/node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"node_modules/react-countdown": {
@ -14337,25 +14373,6 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/react-overlays": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.2.1.tgz",
"integrity": "sha512-GLLSOLWr21CqtJn8geSwQfoJufdt3mfdsnIiQswouuQ2MMPns+ihZklxvsTDKD3cR2tF8ELbi5xUsvqVhR6WvA==",
"dependencies": {
"@babel/runtime": "^7.13.8",
"@popperjs/core": "^2.11.6",
"@restart/hooks": "^0.4.7",
"@types/warning": "^3.0.0",
"dom-helpers": "^5.2.0",
"prop-types": "^15.7.2",
"uncontrollable": "^7.2.1",
"warning": "^4.0.3"
},
"peerDependencies": {
"react": ">=16.3.0",
"react-dom": ">=16.3.0"
}
},
"node_modules/react-resize-detector": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-8.1.0.tgz",
@ -20797,9 +20814,9 @@
}
},
"@popperjs/core": {
"version": "2.11.6",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="
},
"@prisma/client": {
"version": "2.30.3",
@ -20873,6 +20890,14 @@
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
},
"@react-aria/ssr": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.7.0.tgz",
"integrity": "sha512-bfufjg4ESE5giN+Fxj1XIzS5f/YIhqcGc+Ve+vUUKU8xZ8t/Xtjlv8F3kjqDBQdk//n3mluFY7xG1wQVB9rMLQ==",
"requires": {
"@swc/helpers": "^0.5.0"
}
},
"@remusao/guess-url-type": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@remusao/guess-url-type/-/guess-url-type-1.2.1.tgz",
@ -20910,17 +20935,35 @@
"resolved": "https://registry.npmjs.org/@remusao/trie/-/trie-1.4.1.tgz",
"integrity": "sha512-yvwa+aCyYI/UjeD39BnpMypG8N06l86wIDW1/PAc6ihBRnodIfZDwccxQN3n1t74wduzaz74m4ZMHZnB06567Q=="
},
"@restart/context": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz",
"integrity": "sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q=="
},
"@restart/hooks": {
"version": "0.4.7",
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.7.tgz",
"integrity": "sha512-ZbjlEHcG+FQtpDPHd7i4FzNNvJf2enAwZfJbpM8CW7BhmOAbsHpZe3tsHwfQUrBuyrxWqPYp2x5UMnilWcY22A==",
"version": "0.4.11",
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.11.tgz",
"integrity": "sha512-Ft/ncTULZN6ldGHiF/k5qt72O8JyRMOeg0tApvCni8LkoiEahO+z3TNxfXIVGy890YtWVDvJAl662dVJSJXvMw==",
"requires": {
"dequal": "^2.0.2"
"dequal": "^2.0.3"
}
},
"@restart/ui": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.6.tgz",
"integrity": "sha512-eC3puKuWE1SRYbojWHXnvCNHGgf3uzHCb6JOhnF4OXPibOIPEkR1sqDSkL643ydigxwh+ruCa1CmYHlzk7ikKA==",
"requires": {
"@babel/runtime": "^7.21.0",
"@popperjs/core": "^2.11.6",
"@react-aria/ssr": "^3.5.0",
"@restart/hooks": "^0.4.9",
"@types/warning": "^3.0.0",
"dequal": "^2.0.3",
"dom-helpers": "^5.2.0",
"uncontrollable": "^8.0.1",
"warning": "^4.0.3"
},
"dependencies": {
"uncontrollable": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.2.tgz",
"integrity": "sha512-/GDx+K1STGtpgTsj5Dj3J51YaKxZDblbCQHTH1zHLuoBEWodj6MjtRVv3TUijj1JYLRLSFsFzN8NV4M3QV4d9w=="
}
}
},
"@rollup/plugin-babel": {
@ -21347,11 +21390,6 @@
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz",
"integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ=="
},
"@types/invariant": {
"version": "2.2.35",
"resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.35.tgz",
"integrity": "sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg=="
},
"@types/json-schema": {
"version": "7.0.12",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
@ -22521,9 +22559,9 @@
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"bootstrap": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz",
"integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ=="
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.0.tgz",
"integrity": "sha512-UnBV3E3v4STVNQdms6jSGO2CvOkjUMdDAVR2V5N4uCMdaIkaQjbcEAMqRimDHIs4uqBYzDAKCQwCB+97tJgHQw=="
},
"bplist-parser": {
"version": "0.2.0",
@ -29311,27 +29349,34 @@
}
},
"react-bootstrap": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.6.6.tgz",
"integrity": "sha512-pSzYyJT5u4rc8+5myM8Vid2JG52L8AmYSkpznReH/GM4+FhLqEnxUa0+6HRTaGwjdEixQNGchwY+b3xCdYWrDA==",
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.8.0.tgz",
"integrity": "sha512-e/aNtxl0Z2ozrIaR82jr6Zz7ss9GSoaXpQaxmvtDUsTZIq/XalkduR/ZXP6vbQHz2T4syvjA+4FbtwELxxmpww==",
"requires": {
"@babel/runtime": "^7.14.0",
"@restart/context": "^2.1.4",
"@restart/hooks": "^0.4.7",
"@types/invariant": "^2.2.33",
"@types/prop-types": "^15.7.3",
"@types/react": ">=16.14.8",
"@types/react-transition-group": "^4.4.1",
"@types/warning": "^3.0.0",
"classnames": "^2.3.1",
"@babel/runtime": "^7.21.0",
"@restart/hooks": "^0.4.9",
"@restart/ui": "^1.6.3",
"@types/react-transition-group": "^4.4.5",
"classnames": "^2.3.2",
"dom-helpers": "^5.2.1",
"invariant": "^2.2.4",
"prop-types": "^15.7.2",
"prop-types": "^15.8.1",
"prop-types-extra": "^1.1.0",
"react-overlays": "^5.1.2",
"react-transition-group": "^4.4.1",
"react-transition-group": "^4.4.5",
"uncontrollable": "^7.2.1",
"warning": "^4.0.3"
},
"dependencies": {
"prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
}
}
},
"react-countdown": {
@ -29400,21 +29445,6 @@
}
}
},
"react-overlays": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.2.1.tgz",
"integrity": "sha512-GLLSOLWr21CqtJn8geSwQfoJufdt3mfdsnIiQswouuQ2MMPns+ihZklxvsTDKD3cR2tF8ELbi5xUsvqVhR6WvA==",
"requires": {
"@babel/runtime": "^7.13.8",
"@popperjs/core": "^2.11.6",
"@restart/hooks": "^0.4.7",
"@types/warning": "^3.0.0",
"dom-helpers": "^5.2.0",
"prop-types": "^15.7.2",
"uncontrollable": "^7.2.1",
"warning": "^4.0.3"
}
},
"react-resize-detector": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-8.1.0.tgz",

View File

@ -24,7 +24,7 @@
"babel-plugin-inline-react-svg": "^2.0.1",
"bech32": "^2.0.0",
"bolt11": "^1.4.0",
"bootstrap": "^4.6.2",
"bootstrap": "^5.3.0",
"browserslist": "^4.21.4",
"canonical-json": "0.0.4",
"clipboard-copy": "^4.0.1",
@ -59,7 +59,7 @@
"qrcode.react": "^3.1.0",
"react": "^18.2.0",
"react-avatar-editor": "^13.0.0",
"react-bootstrap": "^1.6.6",
"react-bootstrap": "^2.8.0",
"react-countdown": "^2.3.3",
"react-dom": "^18.2.0",
"react-longpressable": "^1.1.1",

View File

@ -1,4 +1,4 @@
import { Image } from 'react-bootstrap'
import Image from 'react-bootstrap/Image'
import { StaticLayout } from '../components/layout'
import styles from '../styles/404.module.css'

View File

@ -1,4 +1,4 @@
import { Image } from 'react-bootstrap'
import Image from 'react-bootstrap/Image'
import { StaticLayout } from '../components/layout'
import styles from '../styles/404.module.css'

View File

@ -60,9 +60,9 @@ function UserItemsHeader ({ type, name }) {
}}
onSubmit={select}
>
<div className='text-muted font-weight-bold mt-0 mb-3 d-flex justify-content-start align-items-center'>
<div className='text-muted fw-bold mt-0 mb-3 d-flex justify-content-start align-items-center'>
<Select
groupClassName='mb-0 mr-2'
groupClassName='mb-0 me-2'
className='w-auto'
name='type'
size='sm'
@ -80,7 +80,7 @@ function UserItemsHeader ({ type, name }) {
/>
for
<Select
groupClassName='mb-0 ml-2'
groupClassName='mb-0 ms-2'
className='w-auto'
name='when'
size='sm'

View File

@ -1,7 +1,7 @@
import Layout from '../../components/layout'
import { gql, useMutation, useQuery } from '@apollo/client'
import UserHeader from '../../components/user-header'
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import styles from '../../styles/user.module.css'
import { useState } from 'react'
import ItemFull from '../../components/item-full'

View File

@ -14,14 +14,16 @@ import ErrorBoundary from '../components/error-boundary'
import { LightningProvider } from '../components/lightning'
import { ServiceWorkerProvider } from '../components/serviceworker'
const SSR = typeof window === 'undefined'
function writeQuery (client, apollo, data) {
if (apollo && data) {
client.writeQuery({
query: gql`${apollo.query}`,
data: data,
variables: apollo.variables,
broadcast: false,
overwrite: true
broadcast: !SSR,
overwrite: SSR
})
}
}
@ -54,7 +56,7 @@ function MyApp ({ Component, pageProps: { session, ...props } }) {
*/
const { apollo, ssrData, me, price, ...otherProps } = props
// if we are on the server, useEffect won't run
if (typeof window === 'undefined' && client) {
if (SSR && client) {
writeQuery(client, apollo, ssrData)
}
useEffect(() => {
@ -64,7 +66,7 @@ function MyApp ({ Component, pageProps: { session, ...props } }) {
return (
<>
<NextNProgress
color='var(--primary)'
color='var(--bs-primary)'
startPosition={0.3}
stopDelayMs={200}
height={2}

View File

@ -1,4 +1,4 @@
import { Image } from 'react-bootstrap'
import Image from 'react-bootstrap/Image'
import { StaticLayout } from '../components/layout'
export default function Email () {

View File

@ -1,6 +1,6 @@
import Layout from '../../components/layout'
import { Form, Input, SubmitButton } from '../../components/form'
import { InputGroup } from 'react-bootstrap'
import InputGroup from 'react-bootstrap/InputGroup'
import { gql, useMutation, useQuery } from '@apollo/client'
import { INVITE_FIELDS } from '../../fragments/invites'
import AccordianItem from '../../components/accordian-item'
@ -58,7 +58,7 @@ function InviteForm () {
required
/>
<Input
label={<>invitee limit <small className='text-muted ml-2'>optional</small></>}
label={<>invitee limit <small className='text-muted ms-2'>optional</small></>}
name='limit'
/>
@ -113,7 +113,7 @@ export default function Invites () {
<h2 className='mt-3 mb-0'>
invite links
</h2>
<small className='d-block text-muted font-weight-bold mx-5'>send these to people you trust, e.g. group chats or DMs</small>
<small className='d-block text-muted fw-bold mx-5'>send these to people you trust, e.g. group chats or DMs</small>
</div>
<InviteForm />
{active.length > 0 && <InviteList name='active' invites={active} />}

View File

@ -2,7 +2,7 @@ import Layout from '../../../components/layout'
import { ITEM_OTS } from '../../../fragments/items'
import { getGetServerSideProps } from '../../../api/ssrApollo'
import stringifyCanon from 'canonical-json'
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import { useQuery } from '@apollo/client'
import { useRouter } from 'next/router'
import PageLoading from '../../../components/page-loading'

View File

@ -23,7 +23,7 @@ export default function Related ({ ssrData }) {
return (
<Layout>
<Item item={item} />
<div className='font-weight-bold my-2'>related</div>
<div className='fw-bold my-2'>related</div>
<Items
ssrData={ssrData}
query={RELATED_ITEMS}

View File

@ -1,4 +1,4 @@
import { Button } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import { CenterLayout } from '../components/layout'
import Snl from '../components/snl'
import { gql } from 'graphql-tag'

View File

@ -39,7 +39,7 @@ export async function getServerSideProps ({ req, res, query: { callbackUrl, erro
function LoginFooter ({ callbackUrl }) {
return (
<small className='font-weight-bold text-muted pt-4'>Don't have an account? <Link href={{ pathname: '/signup', query: { callbackUrl } }}>sign up</Link></small>
<small className='fw-bold text-muted pt-4'>Don't have an account? <Link href={{ pathname: '/signup', query: { callbackUrl } }}>sign up</Link></small>
)
}

View File

@ -1,4 +1,4 @@
import { Image } from 'react-bootstrap'
import Image from 'react-bootstrap/Image'
import { StaticLayout } from '../components/layout'
import styles from '../styles/404.module.css'

View File

@ -35,7 +35,7 @@ export default function Referrals ({ ssrData }) {
const { data } = useQuery(REFERRALS, { variables: { when: router.query.when } })
if (!data && !ssrData) return <PageLoading />
const { referrals: { totalSats, totalReferrals, stats } } = data
const { referrals: { totalSats, totalReferrals, stats } } = data || ssrData
return (
<CenterLayout footerLinks>
@ -44,10 +44,10 @@ export default function Referrals ({ ssrData }) {
when: router.query.when
}}
>
<h4 className='font-weight-bold text-muted text-center pt-5 pb-3 d-flex align-items-center justify-content-center'>
<h4 className='fw-bold text-muted text-center pt-5 pb-3 d-flex align-items-center justify-content-center'>
{totalReferrals} referrals & {totalSats} sats in the last
<Select
groupClassName='mb-0 ml-2'
groupClassName='mb-0 ms-2'
className='w-auto'
name='when'
size='sm'
@ -61,7 +61,7 @@ export default function Referrals ({ ssrData }) {
<div
className='text-small pt-5 px-3 d-flex w-100 align-items-center'
>
<div className='nav-item text-muted pr-2' style={{ 'white-space': 'nowrap' }}>referral link:</div>
<div className='nav-item text-muted pe-2' style={{ 'white-space': 'nowrap' }}>referral link:</div>
<CopyInput
size='sm'
groupClassName='mb-0 w-100'

View File

@ -1,6 +1,7 @@
import { gql } from 'graphql-tag'
import { useEffect, useState } from 'react'
import { Button, InputGroup } from 'react-bootstrap'
import Button from 'react-bootstrap/Button'
import InputGroup from 'react-bootstrap/InputGroup'
import { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from 'recharts'
import { getGetServerSideProps } from '../api/ssrApollo'
import { Form, Input, SubmitButton } from '../components/form'
@ -68,7 +69,7 @@ export default function Rewards ({ ssrData }) {
return (
<CenterLayout footerLinks>
<h4 className='font-weight-bold text-muted text-center'>
<h4 className='fw-bold text-muted text-center'>
<div>
<RewardLine total={total} />
</div>
@ -85,11 +86,11 @@ export default function Rewards ({ ssrData }) {
}
const COLORS = [
'var(--secondary)',
'var(--info)',
'var(--success)',
'var(--boost)',
'var(--grey)'
'var(--bs-secondary)',
'var(--bs-info)',
'var(--bs-success)',
'var(--bs-boost)',
'var(--bs-grey)'
]
function GrowthPieChart ({ data }) {
@ -103,7 +104,7 @@ function GrowthPieChart ({ data }) {
cx='50%'
cy='50%'
outerRadius={80}
fill='var(--secondary)'
fill='var(--bs-secondary)'
label
>
{
@ -151,7 +152,7 @@ export function DonateButton () {
append={<InputGroup.Text className='text-monospace'>sats</InputGroup.Text>}
/>
<div className='d-flex'>
<SubmitButton variant='success' className='ml-auto mt-1 px-4' value='TIP'>donate</SubmitButton>
<SubmitButton variant='success' className='ms-auto mt-1 px-4' value='TIP'>donate</SubmitButton>
</div>
</Form>
))}

View File

@ -79,7 +79,7 @@ function Satus ({ status }) {
return (
<div>
<Icon /><small className={`text-${color} font-weight-bold ml-2`}>{desc}</small>
<Icon /><small className={`text-${color} fw-bold ms-2`}>{desc}</small>
</div>
)
}

View File

@ -1,5 +1,7 @@
import { Checkbox, Form, Input, SubmitButton, Select, VariableInput } from '../components/form'
import { Alert, Button, InputGroup } from 'react-bootstrap'
import Alert from 'react-bootstrap/Alert'
import Button from 'react-bootstrap/Button'
import InputGroup from 'react-bootstrap/InputGroup'
import { CenterLayout } from '../components/layout'
import { useState } from 'react'
import { gql, useMutation, useQuery } from '@apollo/client'
@ -113,7 +115,7 @@ export default function Settings ({ ssrData }) {
label={
<div className='d-flex align-items-center'>turbo zapping
<Info>
<ul className='font-weight-bold'>
<ul className='fw-bold'>
<li>Makes every additional bolt click raise your total zap to another 10x multiple of your default zap</li>
<li>e.g. if your zap default is 10 sats
<ul>
@ -188,7 +190,7 @@ export default function Settings ({ ssrData }) {
label={
<div className='d-flex align-items-center'>hide invoice descriptions
<Info>
<ul className='font-weight-bold'>
<ul className='fw-bold'>
<li>Use this if you don't want funding sources to be linkable to your SN identity.</li>
<li>It makes your invoice descriptions blank.</li>
<li>This only applies to invoices you create
@ -217,7 +219,7 @@ export default function Settings ({ ssrData }) {
label={
<div className='d-flex align-items-center'>wild west mode
<Info>
<ul className='font-weight-bold'>
<ul className='fw-bold'>
<li>don't hide flagged content</li>
<li>don't down rank flagged content</li>
</ul>
@ -231,7 +233,7 @@ export default function Settings ({ ssrData }) {
label={
<div className='d-flex align-items-center'>greeter mode
<Info>
<ul className='font-weight-bold'>
<ul className='fw-bold'>
<li>see and screen free posts and comments</li>
<li>help onboard new stackers to SN and Lightning</li>
<li>you might be subject to more spam</li>
@ -244,16 +246,16 @@ export default function Settings ({ ssrData }) {
<AccordianItem
headerColor='var(--theme-color)'
show={settings?.nostrPubkey}
header={<h4 className='mb-2 text-left'>nostr <small><a href='https://github.com/nostr-protocol/nips/blob/master/05.md' target='_blank' rel='noreferrer'>NIP-05</a></small></h4>}
header={<h4 className='text-left'>nostr <small><a href='https://github.com/nostr-protocol/nips/blob/master/05.md' target='_blank' rel='noreferrer'>NIP-05</a></small></h4>}
body={
<>
<Input
label={<>pubkey <small className='text-muted ml-2'>optional</small></>}
label={<>pubkey <small className='text-muted ms-2'>optional</small></>}
name='nostrPubkey'
clear
/>
<VariableInput
label={<>relays <small className='text-muted ml-2'>optional</small></>}
label={<>relays <small className='text-muted ms-2'>optional</small></>}
name='nostrRelays'
clear
min={0}
@ -263,7 +265,7 @@ export default function Settings ({ ssrData }) {
}
/>
<div className='d-flex'>
<SubmitButton variant='info' className='ml-auto mt-1 px-4'>save</SubmitButton>
<SubmitButton variant='info' className='ms-auto mt-1 px-4'>save</SubmitButton>
</div>
</Form>
<div className='text-left w-100'>
@ -301,7 +303,7 @@ function UnlinkObstacle ({ onClose, type, unlinkAuth }) {
<div>
You are removing your last auth method. It is recommended you link another auth method before removing
your last auth method. If you'd like to proceed anyway, type the following below
<div className='text-danger font-weight-bold my-2'>
<div className='text-danger fw-bold my-2'>
If I logout, even accidentally, I will never be able to access my account again
</div>
<Form
@ -320,7 +322,7 @@ function UnlinkObstacle ({ onClose, type, unlinkAuth }) {
name='warning'
required
/>
<SubmitButton className='d-flex ml-auto' variant='danger'>do it</SubmitButton>
<SubmitButton className='d-flex ms-auto' variant='danger'>do it</SubmitButton>
</Form>
</div>
)
@ -379,7 +381,7 @@ function AuthMethods ({ methods }) {
noForm
/>
<Button
className='ml-2' variant='secondary' onClick={
className='ms-2' variant='secondary' onClick={
async () => {
await unlink('email')
}
@ -448,7 +450,7 @@ export function EmailLinkForm ({ callbackUrl }) {
required
groupClassName='mb-0'
/>
<SubmitButton className='ml-2' variant='secondary'>Link Email</SubmitButton>
<SubmitButton className='ms-2' variant='secondary'>Link Email</SubmitButton>
</div>
</Form>
)

View File

@ -9,14 +9,14 @@ function SignUpHeader () {
<h3 className='w-100 pb-2'>
Sign up
</h3>
<div className='font-weight-bold text-muted pb-4'>Join 15,000+ bitcoiners and start stacking sats today</div>
<div className='fw-bold text-muted pb-4'>Join 15,000+ bitcoiners and start stacking sats today</div>
</>
)
}
function SignUpFooter ({ callbackUrl }) {
return (
<small className='font-weight-bold text-muted pt-4'>Already have an account? <Link href={{ pathname: '/login', query: { callbackUrl } }}>login</Link></small>
<small className='fw-bold text-muted pt-4'>Already have an account? <Link href={{ pathname: '/login', query: { callbackUrl } }}>login</Link></small>
)
}

View File

@ -1,7 +1,8 @@
import { gql } from '@apollo/client'
import { getGetServerSideProps } from '../../api/ssrApollo'
import Layout from '../../components/layout'
import { Col, Row } from 'react-bootstrap'
import Col from 'react-bootstrap/Col'
import Row from 'react-bootstrap/Row'
import { UsageHeader } from '../../components/usage-header'
import { WhenLineChart, WhenAreaChart } from '../../components/when-charts'
import { useRouter } from 'next/router'
@ -65,31 +66,31 @@ export default function Growth ({
<UsageHeader />
<Row>
<Col className='mt-3'>
<div className='text-center text-muted font-weight-bold'>{avg}stackers</div>
<div className='text-center text-muted fw-bold'>{avg}stackers</div>
<WhenLineChart data={stackerGrowth} />
</Col>
<Col className='mt-3'>
<div className='text-center text-muted font-weight-bold'>stacking</div>
<div className='text-center text-muted fw-bold'>stacking</div>
<WhenAreaChart data={stackingGrowth} />
</Col>
</Row>
<Row>
<Col className='mt-3'>
<div className='text-center text-muted font-weight-bold'>{avg}spenders</div>
<div className='text-center text-muted fw-bold'>{avg}spenders</div>
<WhenLineChart data={spenderGrowth} />
</Col>
<Col className='mt-3'>
<div className='text-center text-muted font-weight-bold'>spending</div>
<div className='text-center text-muted fw-bold'>spending</div>
<WhenAreaChart data={spendingGrowth} />
</Col>
</Row>
<Row>
<Col className='mt-3'>
<div className='text-center text-muted font-weight-bold'>registrations</div>
<div className='text-center text-muted fw-bold'>registrations</div>
<WhenAreaChart data={registrationGrowth} />
</Col>
<Col className='mt-3'>
<div className='text-center text-muted font-weight-bold'>items</div>
<div className='text-center text-muted fw-bold'>items</div>
<WhenAreaChart data={itemGrowth} />
</Col>
</Row>

View File

@ -10,7 +10,7 @@ import { WithdrawlSkeleton } from './withdrawals/[id]'
import { useMe } from '../components/me'
import { useEffect, useState } from 'react'
import { requestProvider } from 'webln'
import { Alert } from 'react-bootstrap'
import Alert from 'react-bootstrap/Alert'
import { CREATE_WITHDRAWL, SEND_TO_LNADDR } from '../fragments/wallet'
import { getGetServerSideProps } from '../api/ssrApollo'
import { amountSchema, lnAddrSchema, withdrawlSchema } from '../lib/validate'
@ -37,7 +37,7 @@ function YouHaveSats () {
function WalletHistory () {
return (
<div className='pt-4'>
<Link href='/satistics?inc=invoice,withdrawal' className='text-muted font-weight-bold text-underline'>
<Link href='/satistics?inc=invoice,withdrawal' className='text-muted fw-bold text-underline'>
wallet history
</Link>
</div>
@ -54,7 +54,7 @@ export function WalletForm () {
<Link href='/wallet?type=fund'>
<Button variant='success'>fund</Button>
</Link>
<span className='mx-3 font-weight-bold text-muted'>or</span>
<span className='mx-3 fw-bold text-muted'>or</span>
<Link href='/wallet?type=withdraw'>
<Button variant='success'>withdraw</Button>
</Link>
@ -189,7 +189,7 @@ export function WithdrawlForm () {
/>
<SubmitButton variant='success' className='mt-2'>withdraw</SubmitButton>
</Form>
<span className='my-3 font-weight-bold text-muted'>or via</span>
<span className='my-3 fw-bold text-muted'>or via</span>
<Link href='/wallet?type=lnurl-withdraw'>
<Button variant='grey'>QR code</Button>
</Link>

View File

@ -43,7 +43,7 @@ function LoadWithdrawl () {
const TryMaxFee = () =>
<Link href='/wallet?type=withdraw' className='text-reset text-underline'>
<small className='ml-3'>try increasing max fee</small>
<small className='ms-3'>try increasing max fee</small>
</Link>
let status = 'pending'
@ -54,7 +54,7 @@ function LoadWithdrawl () {
variant = 'confirmed'
break
case 'INSUFFICIENT_BALANCE':
status = <>insufficient balance <small className='ml-3'>contact keyan!</small></>
status = <>insufficient balance <small className='ms-3'>contact keyan!</small></>
variant = 'failed'
break
case 'INVALID_PAYMENT':

View File

@ -25,7 +25,7 @@ export default function Index ({ ssrData }) {
/>
: (
<div className='text-muted text-center mt-5' style={{ fontFamily: 'lightning', fontSize: '2rem', opacity: '0.75' }}>
<Down width={22} height={22} className='mr-2' />search for something<Down width={22} height={22} className='ml-2' />
<Down width={22} height={22} className='me-2' />search for something<Down width={22} height={22} className='ms-2' />
</div>)}
</SearchLayout>
)

View File

@ -37,7 +37,7 @@ const COLORS = {
commentBg: 'rgba(255, 255, 255, 0.04)',
clickToContextColor: 'rgba(255, 255, 255, 0.2)',
color: '#f8f9fa',
brandColor: 'var(--primary)',
brandColor: 'var(--bs-primary)',
grey: '#969696',
link: '#2e99d1',
toolbarActive: 'rgba(255, 255, 255, 0.10)',

View File

@ -1,3 +1,13 @@
$primary: #FADA5E;
$secondary: #F6911D;
$danger: #c03221;
$info: #007cbe;
$success: #5c8001;
$twitter: #1da1f2;
$boost: #8c25f4;
$light: #f8f9fa;
$dark: #212529;
$theme-colors: (
"primary" : #FADA5E,
"secondary" : #F6911D,
@ -6,9 +16,11 @@ $theme-colors: (
"success" : #5c8001,
"twitter" : #1da1f2,
"boost" : #8c25f4,
"light": #f8f9fa,
"dark": #212529,
"grey" : #e9ecef,
"grey-medium" : #d2d2d2,
"grey-darkmode": #8c8c8c
"grey-darkmode": #8c8c8c,
);
$body-bg: #f5f5f7;
@ -20,6 +32,7 @@ $btn-transition: none;
$form-feedback-icon-valid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='12' height='12'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M2 9h3v12H2a1 1 0 0 1-1-1V10a1 1 0 0 1 1-1zm5.293-1.293l6.4-6.4a.5.5 0 0 1 .654-.047l.853.64a1.5 1.5 0 0 1 .553 1.57L14.6 8H21a2 2 0 0 1 2 2v2.104a2 2 0 0 1-.15.762l-3.095 7.515a1 1 0 0 1-.925.619H8a1 1 0 0 1-1-1V8.414a1 1 0 0 1 .293-.707z' fill='rgba(92, 128, 1, 1)'/%3E%3C/svg%3E");
$form-feedback-icon-invalid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='12' height='12'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath d='M22 15h-3V3h3a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1zm-5.293 1.293l-6.4 6.4a.5.5 0 0 1-.654.047L8.8 22.1a1.5 1.5 0 0 1-.553-1.57L9.4 16H3a2 2 0 0 1-2-2v-2.104a2 2 0 0 1 .15-.762L4.246 3.62A1 1 0 0 1 5.17 3H16a1 1 0 0 1 1 1v11.586a1 1 0 0 1-.293.707z' fill='rgba(192,50,33,1)'/%3E%3C/svg%3E");
$line-height-base: 1.75;
$input-placeholder-color: #6c757d;
$input-btn-padding-y: .42rem;
$input-btn-padding-x: .84rem;
$btn-padding-y: .42rem;
@ -33,6 +46,7 @@ $close-text-shadow: none;
$close-color: inherit;
$alert-border-radius: #{33% 2%} / #{11% 74%};
$link-color: #007cbe;
$link-decoration: none;
$font-size-base: .9rem;
$enable-responsive-font-sizes: true;
$link-hover-decoration: none;
@ -42,6 +56,8 @@ $dropdown-link-hover-bg: transparent;
$dropdown-link-active-bg: transparent;
$dropdown-link-color: rgba(0, 0, 0, 0.7);
$dropdown-link-hover-color: rgba(0, 0, 0, 0.9);
$dropdown-item-padding-x: 1.5rem;
$modal-inner-padding: 2rem;
$container-max-widths: (
sm: 540px,
md: 720px,
@ -51,9 +67,20 @@ $nav-link-padding-y: .1rem;
$nav-tabs-link-active-bg: #fff;
$nav-tabs-link-hover-border-color: transparent;
$nav-tabs-link-active-border-color: #ced4da #ced4da $nav-tabs-link-active-bg;
$form-check-input-checked-color: var(--bs-primary);
$form-check-input-checked-bg-color: var(--bs-primary);
$popover-bg: var(--theme-body);
$form-check-input-checked-color: #000;
$tooltip-bg: #5c8001;
$form-select-indicator-color: #808080;
$form-select-indicator: url("data:image/svg+xml, %3Csvg fill='#{$form-select-indicator-color}' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 15.0006L7.75732 10.758L9.17154 9.34375L12 12.1722L14.8284 9.34375L16.2426 10.758L12 15.0006Z'%3E%3C/path%3E%3C/svg%3E%0A");
$form-select-bg-position: right .25rem center;
$form-select-bg-size: 1.5rem;
$popover-body-padding-y: .5rem;
$popover-max-width: 320px !default;
$popover-border-color: var(--theme-borderColor);
@import "~bootstrap/scss/bootstrap";
@import '../node_modules/bootstrap/scss/bootstrap.scss';
@media screen and (min-width: 899px) {
@ -135,8 +162,8 @@ mark {
width: 100% !important;
}
.custom-checkbox.custom-control-inline {
margin-right: .5rem;
.btn-twitter, .btn-twitter:hover, .btn-twitter:active {
color: #ffffff !important;
}
.table {
@ -178,7 +205,7 @@ a:hover {
border-bottom-color: var(--theme-inputBg);
}
select.custom-select,
select,
div[contenteditable],
.form-control {
background-color: var(--theme-inputBg);
@ -186,26 +213,38 @@ div[contenteditable],
border-color: var(--theme-borderColor);
}
.form-group {
margin-bottom: 1rem;
}
select.custom-select {
select.form-select {
background-color: var(--theme-clickToContextColor);
color: var(--theme-dropdownItemColor);
font-weight: bold;
border: none;
background-image: url("data:image/svg+xml, %3Csvg fill='%23808080' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 15.0006L7.75732 10.758L9.17154 9.34375L12 12.1722L14.8284 9.34375L16.2426 10.758L12 15.0006Z'%3E%3C/path%3E%3C/svg%3E%0A");
background-repeat: no-repeat;
background-position: right .25rem center;
background-size: 1.5rem;
display: inline-block;
width: 100%;
height: calc(1.5em + 0.5rem + 2px);
padding: 0.25rem 1.84rem 0.25rem 0.5rem;
font-size: .7875rem;
vertical-align: middle;
border-radius: 0.4rem;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
select.custom-select option {
select option {
// fix dropdown items not visible in darkmode on some browsers
color: initial;
}
select.custom-select:focus {
select:focus {
border-color: none !important;
box-shadow: none !important;
outline: none !important;
}
@ -222,6 +261,7 @@ div[contenteditable]:disabled,
.form-control[readonly] {
background-color: var(--theme-inputDisabledBg);
border-color: var(--theme-borderColor);
color: var(--theme-color);
opacity: 1;
}
@ -296,7 +336,7 @@ div[contenteditable]:disabled,
.dropdown-item.active {
color: var(--theme-brandColor) !important;
text-shadow: 0 0 10px var(--primary);
text-shadow: 0 0 10px var(--bs-primary);
}
.dropdown-divider {
@ -358,6 +398,12 @@ footer {
}
}
.input-group-text {
background-color: var(--theme-clickToContextColor);
border-color: var(--theme-borderColor);
color: var(--theme-color);
}
textarea.form-control,
div[contenteditable] {
line-height: 1rem;
@ -444,12 +490,12 @@ div[contenteditable] {
.dropdown-item.active {
text-shadow: 0 0 10px var(--primary);
text-shadow: 0 0 10px var(--bs-primary);
}
div[contenteditable]:focus,
.form-control:focus {
border-color: var(--primary);
border-color: var(--bs-primary);
}
.btn-secondary,
@ -491,11 +537,11 @@ div[contenteditable]:focus,
}
.fill-secondary {
fill: var(--secondary);
fill: var(--bs-secondary);
}
.fill-boost {
fill: var(--boost);
fill: var(--bs-boost);
}
.fill-white {
@ -503,15 +549,15 @@ div[contenteditable]:focus,
}
.fill-success {
fill: var(--success);
fill: var(--bs-success);
}
.fill-info {
fill: var(--info);
fill: var(--bs-info);
}
.fill-danger {
fill: var(--danger);
fill: var(--bs-danger);
}
.fill-theme-color {

View File

@ -18,6 +18,7 @@
align-items: center;
margin-right: -15px;
padding-right: 15px;
font-family: monospace;
}
.detail {
@ -31,6 +32,10 @@
text-align: center;
}
.sats.head {
font-family: inherit;
}
.head {
font-weight: bold;
text-transform: uppercase;