mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
First round of improving the name and bio modal
refs https://github.com/TryGhost/Team/issues/1756
This commit is contained in:
parent
2629c5704d
commit
20fe790e5d
5 changed files with 169 additions and 81 deletions
|
@ -423,7 +423,7 @@ const Form = (props) => {
|
||||||
handleShowDialog(event, {
|
handleShowDialog(event, {
|
||||||
bioAutofocus: true
|
bioAutofocus: true
|
||||||
});
|
});
|
||||||
}}>{memberBio ? memberBio : 'Add your bio'}
|
}}>{memberBio ? memberBio : 'Add your expertise'}
|
||||||
{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" />}
|
{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" />}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,6 +11,9 @@ const AddNameDialog = (props) => {
|
||||||
const [name, setName] = useState(member.name ?? '');
|
const [name, setName] = useState(member.name ?? '');
|
||||||
const [bio, setBio] = useState(member.bio ?? '');
|
const [bio, setBio] = useState(member.bio ?? '');
|
||||||
|
|
||||||
|
const [exampleProfiles, setExampleProfiles] = useState([]);
|
||||||
|
const [exampleExpertise, setExampleExpertise] = useState('Head of Marketing');
|
||||||
|
|
||||||
const maxBioChars = 50;
|
const maxBioChars = 50;
|
||||||
let initialBioChars = maxBioChars;
|
let initialBioChars = maxBioChars;
|
||||||
if (member.bio) {
|
if (member.bio) {
|
||||||
|
@ -20,6 +23,10 @@ const AddNameDialog = (props) => {
|
||||||
|
|
||||||
const [error, setError] = useState({name: '', bio: ''});
|
const [error, setError] = useState({name: '', bio: ''});
|
||||||
|
|
||||||
|
const stopPropagation = (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
};
|
||||||
|
|
||||||
const close = (succeeded) => {
|
const close = (succeeded) => {
|
||||||
dispatchAction('closePopup');
|
dispatchAction('closePopup');
|
||||||
props.callback(succeeded);
|
props.callback(succeeded);
|
||||||
|
@ -39,8 +46,49 @@ const AddNameDialog = (props) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const generateExampleProfiles = () => {
|
||||||
|
let returnable = [];
|
||||||
|
let dummyData = [
|
||||||
|
{avatar: 'https://images.unsplash.com/photo-1607746882042-944635dfe10e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2670&q=80', name: 'Sophie Joan', expertise: 'Freelance Writer'},
|
||||||
|
{avatar: 'https://images.unsplash.com/photo-1569913486515-b74bf7751574?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1289&q=80', name: 'Naomi Schiff', expertise: 'Founder @ Acme Inc'},
|
||||||
|
{avatar: 'https://images.unsplash.com/photo-1544725176-7c40e5a71c5e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2667&q=80', name: 'Katrina Klosp', expertise: 'Local Resident'},
|
||||||
|
{avatar: 'https://images.unsplash.com/photo-1580489944761-15a19d654956?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1361&q=80', name: 'Laura Smith', expertise: 'Craft Maker'},
|
||||||
|
{avatar: 'https://images.unsplash.com/photo-1633332755192-727a05c4013d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1760&q=80', name: 'Peter Kristy', expertise: 'Design Consultant'},
|
||||||
|
{avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1364&q=80', name: 'Linda Lo', expertise: 'Wedding Photographer'},
|
||||||
|
{avatar: 'https://images.unsplash.com/photo-1527980965255-d3b416303d12?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1760&q=80', name: 'Darren Mckenzie', expertise: 'Senior Engineer'},
|
||||||
|
{avatar: 'https://images.unsplash.com/photo-1566492031773-4f4e44671857?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1287&q=80', name: 'Jack Tomlin', expertise: 'Mid-level UX Designer'}
|
||||||
|
];
|
||||||
|
|
||||||
|
// setup fake users
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
let dummyIndex = Math.floor(Math.random() * dummyData.length);
|
||||||
|
returnable.push(dummyData[dummyIndex]);
|
||||||
|
dummyData.splice(dummyIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnable;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateExampleExpertise = () => {
|
||||||
|
let dummyData = [
|
||||||
|
'Freelance Copywriter',
|
||||||
|
'Head of Marketing',
|
||||||
|
'Junior Developer',
|
||||||
|
'Full-time Parent',
|
||||||
|
'Local Resident',
|
||||||
|
'English Teacher',
|
||||||
|
'Support Officer',
|
||||||
|
'Professional Athlete'
|
||||||
|
];
|
||||||
|
|
||||||
|
return dummyData[Math.floor(Math.random() * dummyData.length)];
|
||||||
|
};
|
||||||
|
|
||||||
// using <input autofocus> breaks transitions in browsers. So we need to use a timer
|
// using <input autofocus> breaks transitions in browsers. So we need to use a timer
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setExampleProfiles(generateExampleProfiles());
|
||||||
|
setExampleExpertise(generateExampleExpertise());
|
||||||
|
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
if (props.bioAutofocus) {
|
if (props.bioAutofocus) {
|
||||||
inputBioRef.current?.focus();
|
inputBioRef.current?.focus();
|
||||||
|
@ -52,12 +100,52 @@ const AddNameDialog = (props) => {
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
};
|
};
|
||||||
}, [inputNameRef]);
|
}, [inputNameRef, inputBioRef]);
|
||||||
|
|
||||||
|
const renderExampleProfile = (index) => {
|
||||||
|
return (exampleProfiles[index] ?
|
||||||
|
<Transition
|
||||||
|
appear
|
||||||
|
enter={`transition duration-200 delay-[400ms] ease-out`}
|
||||||
|
enterFrom="opacity-0 translate-y-2"
|
||||||
|
enterTo="opacity-100 translate-y-0"
|
||||||
|
leave="transition duration-200 ease-in"
|
||||||
|
leaveFrom="opacity-100 translate-y-0"
|
||||||
|
leaveTo="opacity-0 translate-y-2"
|
||||||
|
>
|
||||||
|
<div className="flex flex-row justify-start items-center gap-3 my-4 pr-4">
|
||||||
|
<div className="w-10 h-10 rounded-full border-2 border-white bg-no-repeat bg-cover" style={{backgroundImage: `url(${exampleProfiles[index].avatar})`}} />
|
||||||
|
<div className="flex flex-col justify-center items-start">
|
||||||
|
<div className="text-base font-sans font-semibold tracking-tight text-white">
|
||||||
|
{exampleProfiles[index].name}
|
||||||
|
</div>
|
||||||
|
<div className="font-sans text-[14px] tracking-tight text-neutral-400">
|
||||||
|
{exampleProfiles[index].expertise}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Transition> : null
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
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" onClick={stopPropagation}>
|
||||||
|
<div className="flex">
|
||||||
|
<div className="flex flex-col justify-center items-center w-[40%] bg-[#1C1C1C]">
|
||||||
|
<div className="flex flex-col">
|
||||||
|
{exampleProfiles.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<h1 className="font-sans font-bold tracking-tight text-[24px] mb-3 text-black">Add to your profile</h1>
|
<span>{renderExampleProfile(0)}</span>
|
||||||
<p className="font-sans text-[1.45rem] text-neutral-500 px-4 sm:px-8 leading-9">For a healthy discussion, let other members know who you are when commenting.</p>
|
<span>{renderExampleProfile(1)}</span>
|
||||||
|
<span>{renderExampleProfile(2)}</span>
|
||||||
|
<span>{renderExampleProfile(3)}</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-[60%] p-8">
|
||||||
|
<h1 className="font-sans font-bold tracking-tight text-[24px] mb-1 text-black text-left">Complete your profile.</h1>
|
||||||
|
<p className="font-sans text-base text-neutral-500 pr-4 sm:pr-10 leading-9 text-left">Add context to your comment, share your name and expertise to foster a healthy discussion.</p>
|
||||||
<section className="mt-8 text-left">
|
<section className="mt-8 text-left">
|
||||||
<div className="flex flex-row mb-2 justify-between">
|
<div className="flex flex-row mb-2 justify-between">
|
||||||
<label htmlFor="comments-name" className="font-sans font-medium text-sm">Name</label>
|
<label htmlFor="comments-name" className="font-sans font-medium text-sm">Name</label>
|
||||||
|
@ -92,8 +180,8 @@ const AddNameDialog = (props) => {
|
||||||
}}
|
}}
|
||||||
maxLength="64"
|
maxLength="64"
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-row mt-4 mb-2 justify-between">
|
<div className="flex flex-row mt-6 mb-2 justify-between">
|
||||||
<label htmlFor="comments-name" className="font-sans font-medium text-sm">Bio</label>
|
<label htmlFor="comments-name" className="font-sans font-medium text-sm">Expertise</label>
|
||||||
<div className={`font-sans text-sm text-neutral-400 ${(bioCharsLeft === 0) && 'text-red-500'}`}><b>{bioCharsLeft}</b> characters left</div>
|
<div className={`font-sans text-sm text-neutral-400 ${(bioCharsLeft === 0) && 'text-red-500'}`}><b>{bioCharsLeft}</b> characters left</div>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<input
|
||||||
|
@ -103,7 +191,7 @@ const AddNameDialog = (props) => {
|
||||||
name="bio"
|
name="bio"
|
||||||
ref={inputBioRef}
|
ref={inputBioRef}
|
||||||
value={bio}
|
value={bio}
|
||||||
placeholder="Head of Marketing at Acme, Inc"
|
placeholder={exampleExpertise}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
let bioText = e.target.value;
|
let bioText = e.target.value;
|
||||||
setBioCharsLeft(maxBioChars - bioText.length);
|
setBioCharsLeft(maxBioChars - bioText.length);
|
||||||
|
@ -124,8 +212,10 @@ const AddNameDialog = (props) => {
|
||||||
Save
|
Save
|
||||||
</button>
|
</button>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
<CloseButton close={() => close(false)} />
|
<CloseButton close={() => close(false)} />
|
||||||
</>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {ReactComponent as CloseIcon} from '../../images/icons/close.svg';
|
||||||
|
|
||||||
const CloseButton = (props) => {
|
const CloseButton = (props) => {
|
||||||
return (
|
return (
|
||||||
<button className="transition-opacity duration-100 ease-out absolute top-[36px] sm:top-10 right-8 sm:right-10 opacity-20 hover:opacity-40" onClick={props.close}>
|
<button className="transition-opacity duration-100 ease-out absolute top-[36px] sm:top-10 right-8 sm:right-8 opacity-20 hover:opacity-40" onClick={props.close}>
|
||||||
<CloseIcon className="w-[20px] h-[20px]" />
|
<CloseIcon className="w-[20px] h-[20px]" />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,10 +14,6 @@ const GenericDialog = (props) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopPropagation = (event) => {
|
|
||||||
event.stopPropagation();
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const listener = (event) => {
|
const listener = (event) => {
|
||||||
if (event.key === 'Escape') {
|
if (event.key === 'Escape') {
|
||||||
|
@ -52,9 +48,7 @@ const GenericDialog = (props) => {
|
||||||
leaveFrom="translate-y-0 opacity-100"
|
leaveFrom="translate-y-0 opacity-100"
|
||||||
leaveTo="translate-y-4 opacity-0"
|
leaveTo="translate-y-4 opacity-0"
|
||||||
>
|
>
|
||||||
<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 shadow-modal" onClick={stopPropagation}>
|
|
||||||
{props.children}
|
{props.children}
|
||||||
</div>
|
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
</div>
|
</div>
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
|
|
|
@ -27,6 +27,10 @@ const ReportDialog = (props) => {
|
||||||
|
|
||||||
const {dispatchAction} = useContext(AppContext);
|
const {dispatchAction} = useContext(AppContext);
|
||||||
|
|
||||||
|
const stopPropagation = (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
};
|
||||||
|
|
||||||
const close = (event) => {
|
const close = (event) => {
|
||||||
dispatchAction('closePopup');
|
dispatchAction('closePopup');
|
||||||
};
|
};
|
||||||
|
@ -48,7 +52,7 @@ const ReportDialog = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
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 shadow-modal" onClick={stopPropagation}>
|
||||||
<h1 className="font-sans font-bold tracking-tight text-[24px] mb-3 text-black">You sure you want to report?</h1>
|
<h1 className="font-sans font-bold tracking-tight text-[24px] mb-3 text-black">You sure you want to report?</h1>
|
||||||
<p className="font-sans text-[1.45rem] text-neutral-500">You request will be sent to the owner of this site.</p>
|
<p className="font-sans text-[1.45rem] text-neutral-500">You request will be sent to the owner of this site.</p>
|
||||||
<div className="mt-10">
|
<div className="mt-10">
|
||||||
|
@ -60,7 +64,7 @@ const ReportDialog = (props) => {
|
||||||
</button>
|
</button>
|
||||||
<p className="font-sans font-medium text-[1.45rem] text-neutral-500 mt-4 -mb-1">No, <button className="font-sans underline" onClick={close}>I've changed my mind</button></p>
|
<p className="font-sans font-medium text-[1.45rem] text-neutral-500 mt-4 -mb-1">No, <button className="font-sans underline" onClick={close}>I've changed my mind</button></p>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue