mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Added eslinting to better manage Tailwind classes
This commit is contained in:
parent
455cba4da2
commit
3a29a55228
21 changed files with 950 additions and 756 deletions
21
apps/comments-ui/.eslintrc.js
Normal file
21
apps/comments-ui/.eslintrc.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* eslint-env node */
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: [
|
||||
'react-app',
|
||||
'plugin:ghost/browser'
|
||||
],
|
||||
plugins: [
|
||||
'ghost',
|
||||
'tailwindcss'
|
||||
],
|
||||
rules: {
|
||||
'tailwindcss/classnames-order': 'error',
|
||||
'tailwindcss/enforces-negative-arbitrary-values': 'off',
|
||||
'tailwindcss/enforces-shorthand': 'warn',
|
||||
'tailwindcss/migration-from-tailwind-2': 'warn',
|
||||
'tailwindcss/no-arbitrary-value': 'off',
|
||||
'tailwindcss/no-custom-classname': 'off',
|
||||
'tailwindcss/no-contradicting-classname': 'error'
|
||||
}
|
||||
};
|
|
@ -82,7 +82,9 @@
|
|||
"chalk": "4.1.2",
|
||||
"chokidar": "3.5.2",
|
||||
"copy-webpack-plugin": "6.4.1",
|
||||
"eslint-config-react-app": "^7.0.1",
|
||||
"eslint-plugin-ghost": "2.12.0",
|
||||
"eslint-plugin-tailwindcss": "^3.6.0",
|
||||
"minimist": "1.2.5",
|
||||
"ora": "5.4.1",
|
||||
"postcss": "^8.4.14",
|
||||
|
|
|
@ -70,10 +70,10 @@ const Avatar = (props) => {
|
|||
let avatarEl = (
|
||||
<>
|
||||
{memberName ?
|
||||
(<div className={`flex justify-center items-center rounded-full ${dimensionClasses}`} style={avatarStyle}>
|
||||
<p className={`text-white font-sans font-semibold ${initialsClasses}`}>{ commentGetInitials() }</p>
|
||||
(<div className={`flex items-center justify-center rounded-full ${dimensionClasses}`} style={avatarStyle}>
|
||||
<p className={`font-sans font-semibold text-white ${initialsClasses}`}>{ commentGetInitials() }</p>
|
||||
</div>) :
|
||||
(<div className={`flex justify-center items-center rounded-full bg-neutral-900 dark:bg-[rgba(255,255,255,0.7)] ${dimensionClasses}`}>
|
||||
(<div className={`flex items-center justify-center rounded-full bg-neutral-900 dark:bg-[rgba(255,255,255,0.7)] ${dimensionClasses}`}>
|
||||
<AvatarIcon className="stroke-white dark:stroke-[rgba(0,0,0,0.6)]" />
|
||||
</div>)}
|
||||
{commentMember && <img className={`absolute top-0 left-0 rounded-full ${dimensionClasses}`} src={commentMember.avatar_image} alt="Avatar"/>}
|
||||
|
@ -83,7 +83,7 @@ const Avatar = (props) => {
|
|||
// When an avatar has been deleted or hidden
|
||||
if (props.isBlank) {
|
||||
avatarEl = (
|
||||
<div className={`flex justify-center items-center rounded-full bg-neutral-200 bg-[rgba(200,200,200,0.3)] ${dimensionClasses}`}>
|
||||
<div className={`flex items-center justify-center rounded-full bg-[rgba(200,200,200,0.3)] ${dimensionClasses}`}>
|
||||
<AvatarIcon className="stroke-white dark:opacity-70" />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -23,19 +23,19 @@ const CTABox = (props) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<section className={`flex flex-col items-center pt-[40px] ${member ? 'pb-[32px]' : 'pb-[48px]'} ${!props.isFirst && 'mt-4'} px-2 sm:px-8 border-t-2 border-gray-100 dark:border-gray-100/10 border-b-2`}>
|
||||
<h1 className={`mb-[8px] text-center text-black text-[24px] font-sans tracking-tight dark:text-[rgba(255,255,255,0.85)] ${props.isFirst ? 'font-semibold' : 'font-bold'}`}>
|
||||
<section className={`flex flex-col items-center pt-[40px] ${member ? 'pb-[32px]' : 'pb-[48px]'} ${!props.isFirst && 'mt-4'} border-y-2 border-gray-100 px-2 dark:border-gray-100/10 sm:px-8`}>
|
||||
<h1 className={`mb-[8px] text-center font-sans text-[24px] tracking-tight text-black dark:text-[rgba(255,255,255,0.85)] ${props.isFirst ? 'font-semibold' : 'font-bold'}`}>
|
||||
{titleText}
|
||||
</h1>
|
||||
<p className="mb-[28px] px-0 sm:px-8 w-full sm:max-w-screen-sm font-sans text-[16px] text-center leading-normal text-neutral-600 dark:text-[rgba(255,255,255,0.85)]">
|
||||
<p className="sm:max-w-screen-sm mb-[28px] w-full px-0 text-center font-sans text-[16px] leading-normal text-neutral-600 dark:text-[rgba(255,255,255,0.85)] sm:px-8">
|
||||
Become a {props.isPaid && 'paid'} member of <span className="font-semibold">{publication}</span> to start commenting.
|
||||
</p>
|
||||
<button onClick={handleSignUpClick} className="mb-[12px] text-white font-san py-[14px] px-5 rounded inline-block font-medium leading-none hover:opacity-90 transition-all" style={buttonStyle}>
|
||||
<button onClick={handleSignUpClick} className="font-san mb-[12px] inline-block rounded py-[14px] px-5 font-medium leading-none text-white transition-all hover:opacity-90" style={buttonStyle}>
|
||||
{(props.isPaid && member) ? 'Upgrade now' : 'Sign up now'}
|
||||
</button>
|
||||
{!member && (<p className="text-sm font-sans text-center text-neutral-400 dark:text-[rgba(255,255,255,0.5)]">
|
||||
<span className='inline-block mr-1 text-[15px]'>Already a member?</span>
|
||||
<button onClick={handleSignInClick} className="rounded-md hover:opacity-90 transition-all text-sm font-semibold" style={linkStyle}>Sign in</button>
|
||||
{!member && (<p className="text-center font-sans text-sm text-neutral-400 dark:text-[rgba(255,255,255,0.5)]">
|
||||
<span className='mr-1 inline-block text-[15px]'>Already a member?</span>
|
||||
<button onClick={handleSignInClick} className="rounded-md text-sm font-semibold transition-all hover:opacity-90" style={linkStyle}>Sign in</button>
|
||||
</p>)}
|
||||
</section>
|
||||
);
|
||||
|
|
|
@ -89,25 +89,25 @@ const Comment = ({updateIsEditing = null, isEditing, ...props}) => {
|
|||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className={`flex flex-row w-full ${hasReplies ? 'mb-0' : 'mb-10'}`} data-testid="comment-component">
|
||||
<div className="mr-3 flex flex-col justify-start items-center">
|
||||
<div className={`flex w-full flex-row ${hasReplies ? 'mb-0' : 'mb-10'}`} data-testid="comment-component">
|
||||
<div className="mr-3 flex flex-col items-center justify-start">
|
||||
<div className="flex-0 mb-4">
|
||||
<Avatar comment={comment} saturation={avatarSaturation} isBlank={isNotPublished} />
|
||||
</div>
|
||||
{((!props.isReply && hasReplies) || isInReplyMode) && <div className="w-[3px] h-full mb-2 bg-gradient-to-b from-neutral-100 via-neutral-100 to-transparent dark:from-[rgba(255,255,255,0.05)] dark:via-[rgba(255,255,255,0.05)] grow rounded" />}
|
||||
{((!props.isReply && hasReplies) || isInReplyMode) && <div className="mb-2 h-full w-[3px] grow rounded bg-gradient-to-b from-neutral-100 via-neutral-100 to-transparent dark:from-[rgba(255,255,255,0.05)] dark:via-[rgba(255,255,255,0.05)]" />}
|
||||
</div>
|
||||
<div className="grow">
|
||||
<div className="flex items-start -mt-[3px] mb-2">
|
||||
<div className="-mt-[3px] mb-2 flex items-start">
|
||||
{isNotPublished ?
|
||||
<div className="flex flex-row items-center gap-4 pb-[8px] pr-4 h-12">
|
||||
<p className="font-sans text-[16px] leading-normal text-neutral-300 dark:text-[rgba(255,255,255,0.5)] italic mt-[4px]">{notPublishedMessage}</p>
|
||||
<div className="flex h-12 flex-row items-center gap-4 pb-[8px] pr-4">
|
||||
<p className="mt-[4px] font-sans text-[16px] italic leading-normal text-neutral-300 dark:text-[rgba(255,255,255,0.5)]">{notPublishedMessage}</p>
|
||||
<div className="mt-[4px]">
|
||||
<More comment={comment} toggleEdit={toggleEditMode} />
|
||||
</div>
|
||||
</div> :
|
||||
<div>
|
||||
<h4 className="text-[17px] font-sans font-bold tracking-tight text-[rgb(23,23,23] dark:text-[rgba(255,255,255,0.85)]">{!comment.member ? 'Deleted member' : (comment.member.name ? comment.member.name : 'Anonymous')}</h4>
|
||||
<div className="flex items-baseline font-sans text-[14px] tracking-tight pr-4 text-neutral-400 dark:text-[rgba(255,255,255,0.5)]">
|
||||
<h4 className="text-[rgb(23,23,23] font-sans text-[17px] font-bold tracking-tight dark:text-[rgba(255,255,255,0.85)]">{!comment.member ? 'Deleted member' : (comment.member.name ? comment.member.name : 'Anonymous')}</h4>
|
||||
<div className="flex items-baseline pr-4 font-sans text-[14px] tracking-tight text-neutral-400 dark:text-[rgba(255,255,255,0.5)]">
|
||||
<span>
|
||||
{memberBio && <span>{memberBio}<span className="mx-[0.3em]">·</span></span>}
|
||||
<span title={formatExplicitTime(comment.created_at)}>{formatRelativeTime(comment.created_at)}</span>
|
||||
|
@ -118,12 +118,12 @@ const Comment = ({updateIsEditing = null, isEditing, ...props}) => {
|
|||
</div>
|
||||
|
||||
{!isNotPublished &&
|
||||
<div className="flex flex-row items-center gap-4 mt mb-2 pr-4">
|
||||
<p dangerouslySetInnerHTML={html} className="gh-comment-content font-sans leading-normal text-[16px] text-neutral-900 dark:text-[rgba(255,255,255,0.85)]" data-testid="comment-content"/>
|
||||
<div className="mt mb-2 flex flex-row items-center gap-4 pr-4">
|
||||
<p dangerouslySetInnerHTML={html} className="gh-comment-content font-sans text-[16px] leading-normal text-neutral-900 dark:text-[rgba(255,255,255,0.85)]" data-testid="comment-content"/>
|
||||
</div>}
|
||||
|
||||
{!isNotPublished && (
|
||||
<div className="flex gap-5 items-center">
|
||||
<div className="flex items-center gap-5">
|
||||
{<Like comment={comment} />}
|
||||
{(canReply && (isNotPublished || !props.parent) && <Reply comment={comment} toggleReply={toggleReplyMode} isReplying={isInReplyMode} />)}
|
||||
{<More comment={comment} toggleEdit={toggleEditMode} />}
|
||||
|
|
|
@ -30,18 +30,18 @@ const CommentsBoxTitle = ({title, showCount, count}) => {
|
|||
|
||||
if (count === 1) {
|
||||
return (
|
||||
<div className="text-neutral-400 text-[1.6rem]">1 comment</div>
|
||||
<div className="text-[1.6rem] text-neutral-400">1 comment</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-neutral-400 text-[1.6rem]">{count} comments</div>
|
||||
<div className="text-[1.6rem] text-neutral-400">{count} comments</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full flex justify-between items-baseline font-sans mb-10">
|
||||
<h2 className="font-bold text-[2.8rem] tracking-tight dark:text-[rgba(255,255,255,0.85)]">
|
||||
<div className="mb-10 flex w-full items-baseline justify-between font-sans">
|
||||
<h2 className="text-[2.8rem] font-bold tracking-tight dark:text-[rgba(255,255,255,0.85)]">
|
||||
<Title />
|
||||
</h2>
|
||||
<Count />
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
|
||||
const Empty = (props) => {
|
||||
return (
|
||||
<div className="px-2 pt-0 pb-10 font-sans text-center leading-normal text-neutral-400 dark:text-[rgba(255,255,255,0.85)]">
|
||||
<div className="px-2 pt-0 pb-10 text-center font-sans leading-normal text-neutral-400 dark:text-[rgba(255,255,255,0.85)]">
|
||||
There are currently no comments.
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -5,7 +5,6 @@ import Avatar from './Avatar';
|
|||
import {useEditor, EditorContent} from '@tiptap/react';
|
||||
import {getEditorConfig} from '../utils/editor';
|
||||
import {isMobile} from '../utils/helpers';
|
||||
// import {formatRelativeTime} from '../utils/helpers';
|
||||
import {ReactComponent as SpinnerIcon} from '../images/icons/spinner.svg';
|
||||
import {ReactComponent as EditIcon} from '../images/icons/edit.svg';
|
||||
import {GlobalEventBus} from '../utils/event-bus';
|
||||
|
@ -27,7 +26,7 @@ const Form = (props) => {
|
|||
|
||||
let buttonIcon = null;
|
||||
if (progress === 'sending') {
|
||||
buttonIcon = <SpinnerIcon className="w-[24px] h-[24px] fill-white dark:fill-black" />;
|
||||
buttonIcon = <SpinnerIcon className="h-[24px] w-[24px] fill-white dark:fill-black" />;
|
||||
} else if (progress === 'sent') {
|
||||
buttonIcon = null;
|
||||
}
|
||||
|
@ -408,55 +407,24 @@ const Form = (props) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<form ref={formEl} data-testid="form" onClick={focusEditor} onMouseDown={preventIfFocused} onTouchStart={preventIfFocused} className={`
|
||||
transition duration-200
|
||||
pt-3 pb-2 px-3
|
||||
-mt-[14px] -mx-3 mb-10
|
||||
rounded-md
|
||||
${isFormReallyOpen ? 'cursor-default' : 'cursor-pointer'}
|
||||
${(!props.isReply && !props.isEdit) && '-mt-[4px]'}
|
||||
${(props.isReply || props.isEdit) && '-mt-[20px]'}
|
||||
${shouldFormBeReduced && 'pl-1'}
|
||||
<form ref={formEl} data-testid="form" onClick={focusEditor} onMouseDown={preventIfFocused} onTouchStart={preventIfFocused} className={`-mx-3 -mt-[14px] mb-10 rounded-md px-3 pt-3 pb-2 transition duration-200 ${isFormReallyOpen ? 'cursor-default' : 'cursor-pointer'} ${(!props.isReply && !props.isEdit) && '-mt-[4px]'} ${(props.isReply || props.isEdit) && '-mt-[20px]'} ${shouldFormBeReduced && 'pl-1'}
|
||||
`}>
|
||||
<div className="w-full relative">
|
||||
<div className="relative w-full">
|
||||
<div className="pr-[1px] font-sans leading-normal dark:text-neutral-300">
|
||||
<div className={`transition-[padding] duration-150 delay-100 relative w-full pl-[52px] ${shouldFormBeReduced && 'pl-0'} ${isFormReallyOpen && 'pt-[64px] pl-[1px] sm:pl-[52px]'}`}>
|
||||
<div className={`relative w-full pl-[52px] transition-[padding] delay-100 duration-150 ${shouldFormBeReduced && 'pl-0'} ${isFormReallyOpen && 'pt-[64px] pl-[1px] sm:pl-[52px]'}`}>
|
||||
<div
|
||||
className={`
|
||||
transition-all duration-150 delay-100
|
||||
w-full px-3 py-4
|
||||
bg-white dark:bg-[rgba(255,255,255,0.08)]
|
||||
rounded-md border-none border border-slate-50 dark:border-none
|
||||
font-sans text-[16.5px] leading-normal dark:text-neutral-300
|
||||
focus:outline-0
|
||||
shadow-form hover:shadow-formxl dark:shadow-transparent
|
||||
${commentsCount === 0 && 'placeholder:text-neutral-700'}
|
||||
${isFormReallyOpen ? 'cursor-text min-h-[144px] pb-[68px] pt-2' : 'cursor-pointer overflow-hidden min-h-[48px] hover:border-slate-300'}
|
||||
${props.isEdit && 'cursor-text'}
|
||||
${!memberName && 'pointer-events-none'}
|
||||
className={`w-full rounded-md border border-none border-slate-50 bg-white px-3 py-4 font-sans text-[16.5px] leading-normal shadow-form transition-all delay-100 duration-150 hover:shadow-formxl focus:outline-0 dark:border-none dark:bg-[rgba(255,255,255,0.08)] dark:text-neutral-300 dark:shadow-transparent ${commentsCount === 0 && 'placeholder:text-neutral-700'} ${isFormReallyOpen ? 'min-h-[144px] cursor-text pb-[68px] pt-2' : 'min-h-[48px] cursor-pointer overflow-hidden hover:border-slate-300'} ${props.isEdit && 'cursor-text'} ${!memberName && 'pointer-events-none'}
|
||||
`}>
|
||||
<EditorContent
|
||||
onMouseDown={stopIfFocused} onTouchStart={stopIfFocused}
|
||||
editor={editor}
|
||||
/>
|
||||
</div>
|
||||
<div className="
|
||||
absolute right-[9px] bottom-[9px]
|
||||
flex space-x-4
|
||||
transition-[opacity] duration-150
|
||||
">
|
||||
<div className="absolute right-[9px] bottom-[9px] flex space-x-4 transition-[opacity] duration-150">
|
||||
{(props.isEdit || props.isReply) &&
|
||||
<button type="button" onClick={props.close} className="outline-0 font-sans text-sm font-medium ml-2.5 text-neutral-500 dark:text-neutral-400">Cancel</button>}
|
||||
<button type="button" onClick={props.close} className="ml-2.5 font-sans text-sm font-medium text-neutral-500 outline-0 dark:text-neutral-400">Cancel</button>}
|
||||
<button
|
||||
className={`
|
||||
flex items-center justify-center w-auto sm:w-[128px] ${props.isReply && 'sm:w-[100px]'} ${props.isEdit && 'sm:w-[64px]'} h-[39px]
|
||||
transition-[opacity] duration-150
|
||||
bg-neutral-900 dark:bg-[rgba(255,255,255,0.9)]
|
||||
rounded-[6px] border outline-0
|
||||
py-2 px-3
|
||||
text-sm text-center font-sans font-semibold
|
||||
text-white dark:text-neutral-800
|
||||
`}
|
||||
className={`flex w-auto items-center justify-center sm:w-[128px] ${props.isReply && 'sm:w-[100px]'} ${props.isEdit && 'sm:w-[64px]'} h-[39px] rounded-[6px] border bg-neutral-900 py-2 px-3 text-center font-sans text-sm font-semibold text-white outline-0 transition-[opacity] duration-150 dark:bg-[rgba(255,255,255,0.9)] dark:text-neutral-800`}
|
||||
type="button"
|
||||
data-testid="submit-form-button"
|
||||
onClick={submitForm}
|
||||
|
@ -467,8 +435,8 @@ const Form = (props) => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='absolute top-1 left-0 flex justify-start items-center h-12 w-full'>
|
||||
<div className="grow-0 mr-3">
|
||||
<div className='absolute top-1 left-0 flex h-12 w-full items-center justify-start'>
|
||||
<div className="mr-3 grow-0">
|
||||
<Avatar comment={comment} saturation={avatarSaturation} className="pointer-events-none" />
|
||||
</div>
|
||||
<div className="grow-1 w-full">
|
||||
|
@ -482,7 +450,7 @@ const Form = (props) => {
|
|||
leaveTo="opacity-0"
|
||||
>
|
||||
<div
|
||||
className="text-[17px] font-sans font-bold tracking-tight text-[rgb(23,23,23)] dark:text-[rgba(255,255,255,0.85)]"
|
||||
className="font-sans text-[17px] font-bold tracking-tight text-[rgb(23,23,23)] dark:text-[rgba(255,255,255,0.85)]"
|
||||
onClick={(event) => {
|
||||
handleShowDialog(event, {
|
||||
bioAutofocus: false
|
||||
|
@ -490,13 +458,13 @@ const Form = (props) => {
|
|||
}}>{memberName ? memberName : 'Anonymous'}</div>
|
||||
<div className="flex items-baseline justify-start">
|
||||
<button
|
||||
className={`group transition duration-150 whitespace-nowrap max-w-[80%] sm:max-w-[90%] flex items-center justify-start font-sans text-[14px] text-left tracking-tight text-neutral-400 hover:text-neutral-500 dark:text-[rgba(255,255,255,0.5)] ${!memberBio && 'text-neutral-300 hover:text-neutral-400'}`}
|
||||
className={`group flex max-w-[80%] items-center justify-start whitespace-nowrap text-left font-sans text-[14px] tracking-tight text-neutral-400 transition duration-150 hover:text-neutral-500 dark:text-[rgba(255,255,255,0.5)] sm:max-w-[90%] ${!memberBio && 'text-neutral-300 hover:text-neutral-400'}`}
|
||||
onClick={(event) => {
|
||||
handleShowDialog(event, {
|
||||
bioAutofocus: true
|
||||
});
|
||||
}}><span className="text-ellipsis overflow-hidden ...">{memberBio ? memberBio : 'Add your expertise'}</span>
|
||||
{memberBio && <EditIcon className="transition-all duration-100 ease-out opacity-0 -translate-x-[6px] group-hover:opacity-100 group-hover:translate-x-0 w-[12px] h-[12px] stroke-neutral-500 ml-1" />}
|
||||
}}><span className="... overflow-hidden text-ellipsis">{memberBio ? memberBio : 'Add your expertise'}</span>
|
||||
{memberBio && <EditIcon className="ml-1 h-[12px] w-[12px] -translate-x-[6px] stroke-neutral-500 opacity-0 transition-all duration-100 ease-out group-hover:translate-x-0 group-hover:opacity-100" />}
|
||||
</button>
|
||||
</div>
|
||||
</Transition>
|
||||
|
|
|
@ -35,7 +35,7 @@ function Like(props) {
|
|||
}
|
||||
|
||||
return (
|
||||
<CustomTag className={`group transition-all duration-50 ease-linear flex font-sans items-center text-sm outline-0 ${props.comment.liked ? 'text-neutral-900 dark:text-[rgba(255,255,255,0.9)]' : 'text-neutral-400 dark:text-[rgba(255,255,255,0.5)]'} ${!props.comment.liked && canLike && 'hover:text-neutral-600 hover:dark:text-[rgba(255,255,255,0.3)]'} ${likeCursor}`} onClick={toggleLike} data-testid="like-button">
|
||||
<CustomTag className={`group duration-50 flex items-center font-sans text-sm outline-0 transition-all ease-linear ${props.comment.liked ? 'text-neutral-900 dark:text-[rgba(255,255,255,0.9)]' : 'text-neutral-400 dark:text-[rgba(255,255,255,0.5)]'} ${!props.comment.liked && canLike && 'hover:text-neutral-600 hover:dark:text-[rgba(255,255,255,0.3)]'} ${likeCursor}`} onClick={toggleLike} data-testid="like-button">
|
||||
<LikeIcon className={animationClass + ` mr-[6px] ${props.comment.liked ? 'fill-neutral-900 stroke-neutral-900 dark:fill-white dark:stroke-white' : 'stroke-neutral-400 dark:stroke-[rgba(255,255,255,0.5)'} ${!props.comment.liked && canLike && 'group-hover:stroke-neutral-600'} transition duration-50 ease-linear`} />
|
||||
{props.comment.count.likes}
|
||||
</CustomTag>
|
||||
|
|
|
@ -3,8 +3,8 @@ import {ReactComponent as SpinnerIcon} from '../images/icons/spinner.svg';
|
|||
|
||||
function Loading() {
|
||||
return (
|
||||
<div className="flex items-center justify-center w-full h-32">
|
||||
<SpinnerIcon className="w-12 h-12 mb-6 fill-[rgb(225,225,225,0.9)] dark:fill-[rgba(255,255,255,0.6)]" />
|
||||
<div className="flex h-32 w-full items-center justify-center">
|
||||
<SpinnerIcon className="mb-6 h-12 w-12 fill-[rgb(225,225,225,0.9)] dark:fill-[rgba(255,255,255,0.6)]" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ const More = (props) => {
|
|||
|
||||
return (
|
||||
<div className="relative">
|
||||
{show ? <button onClick={toggleContextMenu} className="outline-0"><MoreIcon className='transition duration-50 ease-linear gh-comments-icon gh-comments-icon-more outline-0 fill-neutral-400 dark:fill-rgba(255,255,255,0.5) hover:fill-neutral-600' /></button> : null}
|
||||
{show ? <button onClick={toggleContextMenu} className="outline-0"><MoreIcon className='duration-50 gh-comments-icon gh-comments-icon-more dark:fill-rgba(255,255,255,0.5) fill-neutral-400 outline-0 transition ease-linear hover:fill-neutral-600' /></button> : null}
|
||||
{isContextMenuOpen ? <CommentContextMenu comment={comment} close={closeContextMenu} toggleEdit={props.toggleEdit} /> : null}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -19,9 +19,9 @@ const Pagination = (props) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<button className="group w-full text-neutral-700 font-semibold px-0 pt-0 pb-2 mb-10 font-sans text-md text-left dark:text-white flex items-center " onClick={loadMore}>
|
||||
<span className="whitespace-nowrap mr-4">↑ Show {left} previous {left === 1 ? 'comment' : 'comments'}</span>
|
||||
<span className="transition-[background-color] duration-200 ease-out inline-block w-full bg-neutral-100 group-hover:bg-neutral-200 dark:bg-[rgba(255,255,255,0.05)] rounded h-[3px] mt-[3px]" />
|
||||
<button className="group mb-10 flex w-full items-center px-0 pt-0 pb-2 text-left font-sans text-md font-semibold text-neutral-700 dark:text-white " onClick={loadMore}>
|
||||
<span className="mr-4 whitespace-nowrap">↑ Show {left} previous {left === 1 ? 'comment' : 'comments'}</span>
|
||||
<span className="mt-[3px] inline-block h-[3px] w-full rounded bg-neutral-100 transition-[background-color] duration-200 ease-out group-hover:bg-neutral-200 dark:bg-[rgba(255,255,255,0.05)]" />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -5,8 +5,8 @@ const RepliesPagination = (props) => {
|
|||
const count = props.count;
|
||||
|
||||
return (
|
||||
<button className="group w-full text-neutral-700 font-semibold mt-10 sm:mt-0 mb-10 font-sans text-md text-left dark:text-white flex items-center " onClick={loadMore} data-testid="reply-pagination-button">
|
||||
<span className="whitespace-nowrap mr-4">↓ Show {count} more {count === 1 ? 'reply' : 'replies'}</span>
|
||||
<button className="group my-10 flex w-full items-center text-left font-sans text-md font-semibold text-neutral-700 dark:text-white sm:mt-0" onClick={loadMore} data-testid="reply-pagination-button">
|
||||
<span className="mr-4 whitespace-nowrap">↓ Show {count} more {count === 1 ? 'reply' : 'replies'}</span>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -6,8 +6,8 @@ function Reply(props) {
|
|||
const {member} = useContext(AppContext);
|
||||
|
||||
return member ?
|
||||
(<button disabled={!!props.disabled} className={`group transition-all duration-50 ease-linear flex font-sans items-center text-sm outline-0 ${props.isReplying ? 'text-neutral-900 dark:text-[rgba(255,255,255,0.9)]' : 'text-neutral-500 hover:text-neutral-600 dark:text-[rgba(255,255,255,0.5)] dark:hover:text-[rgba(255,255,255,0.3)]'}`} onClick={props.toggleReply} data-testid="reply-button">
|
||||
<ReplyIcon className={`mr-[6px] ${props.isReplying ? 'fill-neutral-900 stroke-neutral-900 dark:fill-white dark:stroke-white' : 'stroke-neutral-400 dark:stroke-[rgba(255,255,255,0.5)] group-hover:stroke-neutral-600'} transition duration-50 ease-linear`} />Reply
|
||||
(<button disabled={!!props.disabled} className={`group duration-50 flex items-center font-sans text-sm outline-0 transition-all ease-linear ${props.isReplying ? 'text-neutral-900 dark:text-[rgba(255,255,255,0.9)]' : 'text-neutral-500 hover:text-neutral-600 dark:text-[rgba(255,255,255,0.5)] dark:hover:text-[rgba(255,255,255,0.3)]'}`} onClick={props.toggleReply} data-testid="reply-button">
|
||||
<ReplyIcon className={`mr-[6px] ${props.isReplying ? 'fill-neutral-900 stroke-neutral-900 dark:fill-white dark:stroke-white' : 'stroke-neutral-400 group-hover:stroke-neutral-600 dark:stroke-[rgba(255,255,255,0.5)]'} duration-50 transition ease-linear`} />Reply
|
||||
</button>) : null;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,9 +74,9 @@ const AddNameDialog = (props) => {
|
|||
leaveTo="opacity-0 translate-y-2"
|
||||
key={profile.name}
|
||||
>
|
||||
<div className="flex flex-row justify-start items-center gap-3 pr-4">
|
||||
<div className="w-10 h-10 rounded-full border-2 border-white bg-no-repeat bg-cover" style={{backgroundImage: `url(${profile.avatar})`}} />
|
||||
<div className="flex flex-col justify-center items-start">
|
||||
<div className="flex flex-row items-center justify-start gap-3 pr-4">
|
||||
<div className="h-10 w-10 rounded-full border-2 border-white bg-cover bg-no-repeat" style={{backgroundImage: `url(${profile.avatar})`}} />
|
||||
<div className="flex flex-col items-start justify-center">
|
||||
<div className="text-base font-sans font-semibold tracking-tight text-white">
|
||||
{profile.name}
|
||||
</div>
|
||||
|
@ -107,21 +107,21 @@ const AddNameDialog = (props) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="overflow-hidden relative bg-white w-screen sm:w-[720px] h-screen sm:h-auto p-[28px] sm:p-0 rounded-none sm:rounded-xl text-center shadow-modal" onMouseDown={stopPropagation}>
|
||||
<div className="rounded-none relative h-screen w-screen overflow-hidden bg-white p-[28px] text-center shadow-modal sm:h-auto sm:w-[720px] sm:rounded-xl sm:p-0" onMouseDown={stopPropagation}>
|
||||
<div className="flex">
|
||||
{!isMobile() &&
|
||||
<div className={`flex flex-col justify-center items-center w-[40%] bg-[#1C1C1C]`}>
|
||||
<div className="flex flex-col gap-9 -mt-[1px]">
|
||||
<div className={`flex w-[40%] flex-col items-center justify-center bg-[#1C1C1C]`}>
|
||||
<div className="-mt-[1px] flex flex-col gap-9">
|
||||
{renderExampleProfiles()}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div className={`${isMobile() ? 'w-full' : 'w-[60%]'} p-0 sm:p-8`}>
|
||||
<h1 className="font-sans font-bold tracking-tight text-[24px] mb-1 text-black text-center sm:text-left">Complete your profile<span className="hidden sm:inline">.</span></h1>
|
||||
<p className="font-sans text-base text-neutral-500 pr-0 sm:pr-10 leading-9 text-center sm:text-left">Add context to your comment, share your name and expertise to foster a healthy discussion.</p>
|
||||
<h1 className="mb-1 text-center font-sans text-[24px] font-bold tracking-tight text-black sm:text-left">Complete your profile<span className="hidden sm:inline">.</span></h1>
|
||||
<p className="text-base pr-0 text-center font-sans leading-9 text-neutral-500 sm:pr-10 sm:text-left">Add context to your comment, share your name and expertise to foster a healthy discussion.</p>
|
||||
<section className="mt-8 text-left">
|
||||
<div className="flex flex-row mb-2 justify-between">
|
||||
<label htmlFor="comments-name" className="font-sans font-semibold text-[1.3rem]">Name</label>
|
||||
<div className="mb-2 flex flex-row justify-between">
|
||||
<label htmlFor="comments-name" className="font-sans text-[1.3rem] font-semibold">Name</label>
|
||||
<Transition
|
||||
show={!!error.name}
|
||||
enter="transition duration-300 ease-out"
|
||||
|
@ -136,7 +136,7 @@ const AddNameDialog = (props) => {
|
|||
</div>
|
||||
<input
|
||||
id="comments-name"
|
||||
className={`transition-[border-color] duration-200 font-sans text-[16px] px-3 rounded border border-neutral-200 focus:border-neutral-300 w-full outline-0 h-[42px] flex items-center ${error.name && 'border-red-500 focus:border-red-500'}`}
|
||||
className={`flex h-[42px] w-full items-center rounded border border-neutral-200 px-3 font-sans text-[16px] outline-0 transition-[border-color] duration-200 focus:border-neutral-300 ${error.name && 'border-red-500 focus:border-red-500'}`}
|
||||
type="text"
|
||||
name="name"
|
||||
ref={inputNameRef}
|
||||
|
@ -153,13 +153,13 @@ const AddNameDialog = (props) => {
|
|||
}}
|
||||
maxLength="64"
|
||||
/>
|
||||
<div className="flex flex-row mt-6 mb-2 justify-between">
|
||||
<label htmlFor="comments-name" className="font-sans font-semibold text-[1.3rem]">Expertise</label>
|
||||
<div className="mt-6 mb-2 flex flex-row justify-between">
|
||||
<label htmlFor="comments-name" className="font-sans text-[1.3rem] font-semibold">Expertise</label>
|
||||
<div className={`font-sans text-[1.3rem] text-neutral-400 ${(bioCharsLeft === 0) && 'text-red-500'}`}><b>{bioCharsLeft}</b> characters left</div>
|
||||
</div>
|
||||
<input
|
||||
id="comments-bio"
|
||||
className={`transition-[border-color] duration-200 font-sans text-[16px] px-3 rounded border border-neutral-200 focus:border-neutral-300 w-full outline-0 h-[42px] flex items-center ${(bioCharsLeft === 0) && 'border-red-500 focus:border-red-500'}`}
|
||||
className={`flex h-[42px] w-full items-center rounded border border-neutral-200 px-3 font-sans text-[16px] outline-0 transition-[border-color] duration-200 focus:border-neutral-300 ${(bioCharsLeft === 0) && 'border-red-500 focus:border-red-500'}`}
|
||||
type="text"
|
||||
name="bio"
|
||||
ref={inputBioRef}
|
||||
|
@ -179,7 +179,7 @@ const AddNameDialog = (props) => {
|
|||
maxLength={maxBioChars}
|
||||
/>
|
||||
<button
|
||||
className={`transition-opacity duration-200 ease-linear w-full h-[42px] mt-10 px-8 flex items-center justify-center rounded-md text-white font-sans font-semibold text-[15px] opacity-100 hover:opacity-90`}
|
||||
className={`mt-10 flex h-[42px] w-full items-center justify-center rounded-md px-8 font-sans text-[15px] font-semibold text-white opacity-100 transition-opacity duration-200 ease-linear hover:opacity-90`}
|
||||
style={{backgroundColor: accentColor ?? '#000000'}}
|
||||
onClick={submit}
|
||||
>
|
||||
|
|
|
@ -11,7 +11,7 @@ const AuthorContextMenu = (props) => {
|
|||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<button className="w-full mb-3 text-left text-[14px]" onClick={props.toggleEdit}>
|
||||
<button className="mb-3 w-full text-left text-[14px]" onClick={props.toggleEdit}>
|
||||
Edit
|
||||
</button>
|
||||
<button className="w-full text-left text-[14px] text-red-600" onClick={deleteComment}>
|
||||
|
|
|
@ -3,8 +3,8 @@ import {ReactComponent as CloseIcon} from '../../images/icons/close.svg';
|
|||
|
||||
const CloseButton = (props) => {
|
||||
return (
|
||||
<button className="transition-opacity duration-100 ease-out absolute top-6 sm:top-10 right-6 sm:right-8 opacity-20 hover:opacity-40" onClick={props.close}>
|
||||
<CloseIcon className="w-[20px] h-[20px]" />
|
||||
<button className="absolute top-6 right-6 opacity-20 transition-opacity duration-100 ease-out hover:opacity-40 sm:top-10 sm:right-8" onClick={props.close}>
|
||||
<CloseIcon className="h-[20px] w-[20px]" />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -73,7 +73,7 @@ const CommentContextMenu = (props) => {
|
|||
|
||||
return (
|
||||
<div ref={element} onClick={stopPropagation}>
|
||||
<div className="min-w-min sm:min-w-[150px] bg-white absolute font-sans rounded py-3 pl-4 pr-8 shadow-lg text-sm whitespace-nowrap z-10 dark:bg-zinc-900 dark:text-white outline-0">
|
||||
<div className="absolute z-10 min-w-min whitespace-nowrap rounded bg-white py-3 pl-4 pr-8 font-sans text-sm shadow-lg outline-0 dark:bg-zinc-900 dark:text-white sm:min-w-[150px]">
|
||||
{contextMenu}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -39,7 +39,7 @@ const GenericDialog = (props) => {
|
|||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className="fixed top-0 left-0 overflow-hidden w-screen h-screen flex pt-0 sm:pt-12 justify-center bg-gradient-to-b from-[rgba(0,0,0,0.2)] to-rgba(0,0,0,0.1) backdrop-blur-[2px]" onMouseDown={close}>
|
||||
<div className="to-rgba(0,0,0,0.1) fixed top-0 left-0 flex h-screen w-screen justify-center overflow-hidden bg-gradient-to-b from-[rgba(0,0,0,0.2)] pt-0 backdrop-blur-[2px] sm:pt-12" onMouseDown={close}>
|
||||
<Transition.Child
|
||||
enter="transition duration-200 delay-150 linear"
|
||||
enterFrom="translate-y-4 opacity-0"
|
||||
|
|
|
@ -22,9 +22,9 @@ const ReportDialog = (props) => {
|
|||
|
||||
let buttonIcon = null;
|
||||
if (progress === 'sending') {
|
||||
buttonIcon = <SpinnerIcon className="w-[24px] h-[24px] mr-2 fill-white" />;
|
||||
buttonIcon = <SpinnerIcon className="mr-2 h-[24px] w-[24px] fill-white" />;
|
||||
} else if (progress === 'sent') {
|
||||
buttonIcon = <SuccessIcon className="w-[16px] h-[16px] mr-2" />;
|
||||
buttonIcon = <SuccessIcon className="mr-2 h-[16px] w-[16px]" />;
|
||||
}
|
||||
|
||||
const stopPropagation = (event) => {
|
||||
|
@ -52,12 +52,12 @@ const ReportDialog = (props) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="relative bg-white w-screen sm:w-[500px] h-screen sm:h-auto p-[28px] sm:p-8 rounded-none sm:rounded-xl text-center sm:text-left shadow-modal" onMouseDown={stopPropagation}>
|
||||
<h1 className="font-sans font-bold tracking-tight text-[24px] mb-1 text-black">You want to report<span className="hidden sm:inline"> this comment</span>?</h1>
|
||||
<p className="font-sans text-base text-neutral-500 px-4 sm:pr-4 sm:pl-0 leading-9">Your request will be sent to the owner of this site.</p>
|
||||
<div className="flex flex-col sm:flex-row justify-start items-center gap-4 mt-10">
|
||||
<div className="rounded-none relative h-screen w-screen bg-white p-[28px] text-center shadow-modal sm:h-auto sm:w-[500px] sm:rounded-xl sm:p-8 sm:text-left" onMouseDown={stopPropagation}>
|
||||
<h1 className="mb-1 font-sans text-[24px] font-bold tracking-tight text-black">You want to report<span className="hidden sm:inline"> this comment</span>?</h1>
|
||||
<p className="text-base px-4 font-sans leading-9 text-neutral-500 sm:pr-4 sm:pl-0">Your request will be sent to the owner of this site.</p>
|
||||
<div className="mt-10 flex flex-col items-center justify-start gap-4 sm:flex-row">
|
||||
<button
|
||||
className={`transition duration-200 ease-linear w-full sm:w-[200px] h-[44px] px-4 flex items-center justify-center rounded-md text-white font-sans font-semibold text-[15px] ${buttonColor} opacity-100 hover:opacity-90`}
|
||||
className={`flex h-[44px] w-full items-center justify-center rounded-md px-4 font-sans text-[15px] font-semibold text-white transition duration-200 ease-linear sm:w-[200px] ${buttonColor} opacity-100 hover:opacity-90`}
|
||||
onClick={submit}
|
||||
style={{backgroundColor: buttonColor ?? '#000000'}}
|
||||
>
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue