Profile page redesign #510

Merged
franknoirot merged 11 commits from profile-page into main 2021-09-18 07:16:33 +02:00
8 changed files with 125 additions and 104 deletions
Showing only changes of commit 34757cf535 - Show all commits

View File

@@ -22,6 +22,7 @@ module.exports = {
800: '#1A1A1D',
750: '#222222',
760: '#232532',
710: '#2B303C', // TODO: Use HSL so I stop adding grays to fix the warm/cool problem
700: '#2A3038',
600: '#3B3E4B',
550: '#63636A',

View File

@@ -11,6 +11,7 @@ import ProfileSlashLogin from 'src/components/ProfileSlashLogin'
import Gravatar from 'src/components/Gravatar/Gravatar'
import EditableProjectTitle from 'src/components/EditableProjecTitle/EditableProjecTitle'
import CaptureButton from 'src/components/CaptureButton/CaptureButton'
import { ReactNode } from 'react'
const TopButton = ({
onClick,
@@ -44,6 +45,7 @@ interface IdeHeaderProps {
projectOwnerId?: string
projectOwnerImage?: string
projectId?: string
children?: ReactNode
}
const IdeHeader = ({
@@ -53,6 +55,7 @@ const IdeHeader = ({
projectOwnerImage,
projectId,
projectOwnerId,
children,
}: IdeHeaderProps) => {
const { currentUser } = useAuth()
const { project } = useIdeContext()
@@ -92,87 +95,16 @@ const IdeHeader = ({
<div />
)}
<div className="text-gray-200 grid grid-flow-col-dense gap-4 mr-4 items-center">
{canEdit && !projectTitle && (
<CaptureButton
{ (!children)
? <DefaultTopButtons
project={project}
projectTitle={projectTitle}
_projectOwner={_projectOwner}
handleRender={handleRender}
canEdit={canEdit}
projectTitle={project?.title}
userName={project?.user?.userName}
shouldUpdateImage={!project?.mainImage}
TheButton={({ onClick }) => (
<TopButton
onClick={onClick}
name="Save Project Image"
className=" bg-ch-blue-650 bg-opacity-30 hover:bg-opacity-80 text-ch-gray-300"
>
<Svg name="camera" className="w-6 h-6 text-ch-blue-400" />
</TopButton>
)}
/>
)}
{!projectTitle && (
<TopButton
className="bg-ch-pink-800 bg-opacity-30 hover:bg-opacity-80 text-ch-gray-300"
onClick={handleRender}
name={canEdit ? 'Save' : 'Preview'}
>
<Svg
name={canEdit ? 'floppy-disk' : 'photograph'}
className="w-6 h-6 text-ch-pink-500"
/>
</TopButton>
)}
{projectTitle && (
<TopButton
className="bg-ch-pink-800 bg-opacity-30 hover:bg-opacity-80 text-ch-gray-300"
onClick={() =>
navigate(routes.ide({ userName: _projectOwner, projectTitle }))
}
name="Editor"
>
<Svg name="terminal" className="w-6 h-6 text-ch-pink-500" />
</TopButton>
)}
<Popover className="relative outline-none w-full h-full">
{({ open }) => {
return (
<>
<Popover.Button className="h-full w-full outline-none">
<TopButton
Tag="div"
name="Share"
className=" bg-ch-purple-400 bg-opacity-30 hover:bg-opacity-80 text-ch-gray-300"
>
<Svg
name="share"
className="w-6 h-6 text-ch-purple-500 mt-1"
/>
</TopButton>
</Popover.Button>
{open && (
<Popover.Panel className="absolute z-10 mt-4 right-0">
<Tabs
className="bg-ch-purple-gray-200 rounded-md shadow-md overflow-hidden text-gray-700"
selectedTabClassName="bg-ch-gray-700 text-white"
>
<TabPanel>
<FullScriptEncoding />
</TabPanel>
<TabPanel>
<ExternalScript />
</TabPanel>
<TabList className="flex whitespace-nowrap text-gray-700 border-t border-gray-700">
<Tab className="p-3 px-5">encoded script</Tab>
<Tab className="p-3 px-5">external script</Tab>
</TabList>
</Tabs>
</Popover.Panel>
)}
</>
)
}}
</Popover>
: children
}
{/* <TopButton>Fork</TopButton> */}
<div className="h-8 w-8">
<NavPlusButton />
@@ -184,3 +116,89 @@ const IdeHeader = ({
}
export default IdeHeader
function DefaultTopButtons({ project, projectTitle, _projectOwner, handleRender, canEdit }) {
return (<>
{canEdit && !projectTitle && (
<CaptureButton
canEdit={canEdit}
projectTitle={project?.title}
userName={project?.user?.userName}
shouldUpdateImage={!project?.mainImage}
TheButton={({ onClick }) => (
<TopButton
onClick={onClick}
name="Save Project Image"
className=" bg-ch-blue-650 bg-opacity-30 hover:bg-opacity-80 text-ch-gray-300"
>
<Svg name="camera" className="w-6 h-6 text-ch-blue-400" />
</TopButton>
)}
/>
)}
{!projectTitle && (
<TopButton
className="bg-ch-pink-800 bg-opacity-30 hover:bg-opacity-80 text-ch-gray-300"
onClick={handleRender}
name={canEdit ? 'Save' : 'Preview'}
>
franknoirot commented 2021-09-12 20:12:23 +02:00 (Migrated from github.com)
Review

Not sure this is the right move but I made it so a component could override the default buttons by bringing their own as children to it. It let me remove them by providing a dummy element without effecting any other pages.

Not sure this is the right move but I made it so a component could override the default buttons by bringing their own as children to it. It let me remove them by providing a dummy element without effecting any other pages.
Irev-Dev commented 2021-09-14 13:04:13 +02:00 (Migrated from github.com)
Review

Hmm I was trying to figure out what this even needed to be modified for the profile page but because this essentially the top nav bar.

I think this approach is good.

Perhaps later we'll look to remove MainLayout.js and replace it with the component everywhere. i.e. it can be the have the search bar for the projects explorer etc. If we do that than displaying children ONLY is probably better, i.e. it will need DefaultTopButtons to be passed in, in this case.

This is good though.

Hmm I was trying to figure out what this even needed to be modified for the profile page but because this essentially the top nav bar. I think this approach is good. Perhaps later we'll look to remove `MainLayout.js` and replace it with the component everywhere. i.e. it can be the have the search bar for the projects explorer etc. If we do that than displaying children ONLY is probably better, i.e. it will need `DefaultTopButtons` to be passed in, in this case. This is good though.
franknoirot commented 2021-09-15 03:12:15 +02:00 (Migrated from github.com)
Review

Yes I like that idea about MainLayout, it's feeling about ready to be taken out after a little refactor of this header to cover more use cases.

Yes I like that idea about `MainLayout`, it's feeling about ready to be taken out after a little refactor of this header to cover more use cases.
<Svg
name={canEdit ? 'floppy-disk' : 'photograph'}
className="w-6 h-6 text-ch-pink-500"
/>
</TopButton>
)}
{projectTitle && (
<TopButton
className="bg-ch-pink-800 bg-opacity-30 hover:bg-opacity-80 text-ch-gray-300"
onClick={() =>
navigate(routes.ide({ userName: _projectOwner, projectTitle }))
}
name="Editor"
>
<Svg name="terminal" className="w-6 h-6 text-ch-pink-500" />
</TopButton>
)}
<Popover className="relative outline-none w-full h-full">
{({ open }) => {
return (
<>
<Popover.Button className="h-full w-full outline-none">
<TopButton
Tag="div"
name="Share"
className=" bg-ch-purple-400 bg-opacity-30 hover:bg-opacity-80 text-ch-gray-300"
>
<Svg
name="share"
className="w-6 h-6 text-ch-purple-500 mt-1"
/>
</TopButton>
</Popover.Button>
{open && (
<Popover.Panel className="absolute z-10 mt-4 right-0">
<Tabs
className="bg-ch-purple-gray-200 rounded-md shadow-md overflow-hidden text-gray-700"
selectedTabClassName="bg-ch-gray-700 text-white"
>
<TabPanel>
<FullScriptEncoding />
</TabPanel>
<TabPanel>
<ExternalScript />
</TabPanel>
<TabList className="flex whitespace-nowrap text-gray-700 border-t border-gray-700">
<Tab className="p-3 px-5">encoded script</Tab>
<Tab className="p-3 px-5">external script</Tab>
</TabList>
</Tabs>
</Popover.Panel>
)}
</>
)
}}
</Popover>
</>)
}

View File

@@ -11,13 +11,13 @@ import Svg from 'src/components/Svg'
const CLOUDINARY_UPLOAD_PRESET = 'CadHub_project_images'
const CLOUDINARY_UPLOAD_URL = 'https://api.cloudinary.com/v1_1/irevdev/upload'
export function ImageFallback({ width = 100, cloudinaryId = 'CadHub/eia1kwru54g2kf02s2xx', className = '' }) {
export function ImageFallback({ width = 100, imageId = 'CadHub/eia1kwru54g2kf02s2xx', className = '' }) {
franknoirot commented 2021-09-12 20:15:15 +02:00 (Migrated from github.com)
Review

Having a component that got that fallback user image without the image uploading functionality made me able to migrate the signed-in popover to HeadlessUI from MaterialUI, because I couldn't have a button within a button. I figured it's okay because the use case for the top nav (and ProjectCard) don't ever need the upload functionality.

Having a component that got that fallback user image without the image uploading functionality made me able to migrate the signed-in popover to HeadlessUI from MaterialUI, because I couldn't have a button within a button. I figured it's okay because the use case for the top nav (and `ProjectCard`) don't ever need the upload functionality.
Irev-Dev commented 2021-09-14 12:46:08 +02:00 (Migrated from github.com)
Review

That button within a button error in the console has been annoying me for ages, but obviously I hadn't done anything about, so thanks!

That button within a button error in the console has been annoying me for ages, but obviously I hadn't done anything about, so thanks!
return (
<div className="relative overflow-hidden w-full h-full">
Irev-Dev commented 2021-09-14 13:06:34 +02:00 (Migrated from github.com)
Review

not relevant to this PR, but I do think there must be a better way of doing a fallback/empty-state than this image.

not relevant to this PR, but I do think there must be a better way of doing a fallback/empty-state than this image.
franknoirot commented 2021-09-14 14:12:47 +02:00 (Migrated from github.com)
Review

I hear that. I'll add to my list, maybe Cloudinary has a documented best.

I hear that. I'll add to my list, maybe Cloudinary has a documented best.
<CloudinaryImage
className={"object-cover w-full h-full shadow overflow-hidden " + className }
cloudName="irevdev"
publicId={cloudinaryId}
publicId={imageId}
width={width}
crop="scale"
/>
@@ -78,20 +78,19 @@ export default function ImageUploader({
}
style={{ paddingBottom: `${(1 / aspectRatio) * 100}%` }}
>
<div className="absolute w-full h-full" {...getRootProps()}>
<div className="absolute w-full h-full inset-0" {...getRootProps()}>
{cloudinaryId && isEditable && (
<button className="absolute z-10 bg-indigo-900 opacity-75 bottom-0 right-0 flex items-center p-1 mb-6 mr-2 rounded-lg">
<span className="text-gray-100 pr-2">Update</span>
<button className="w-full py-1 absolute z-10 bg-ch-blue-650 bg-opacity-50 hover:bg-opacity-80 bottom-0 right-0 left-0 flex items-center justify-center text-ch-gray-300">
<span className="font-fira-code text-sm leading-4">Update</span>
<Svg
name="pencil"
strokeWidth={2}
className=" text-gray-100 h-6 w-6"
name="pencil-solid"
className=" h-4 w-4 ml-4 mb-2"
/>
</button>
)}
{isEditable && <input {...getInputProps()} />}
{(cloudinaryId || !isEditable) && (
<ImageFallback cloudinaryId={cloudinaryId} width={width} />
<ImageFallback imageId={cloudinaryId} width={width} />
)}
{!cloudinaryId && <button className="absolute inset-0"></button>}
{!cloudinaryId && isEditable && (

View File

@@ -25,17 +25,17 @@ const KeyValue = ({
return (
<div className={"flex flex-col " + className}>
<div className={"text-ch-blue-400 font-fira-code flex items-center leading-4 text-sm whitespace-nowrap " + (bottom ? "order-2" : "")}>
{keyName}
<span className={isEditable ? "text-ch-blue-300" : ""}>{keyName}</span>
{canEdit &&
(isEditable ? (
<button
className="font-fira-sans items-center ml-4 grid grid-flow-col-dense p-px px-2 gap-2 bg-ch-purple-400 bg-opacity-30 hover:bg-opacity-80 rounded-sm border border-ch-purple-400"
className="font-fira-sans text-ch-gray-300 items-center ml-4 grid grid-flow-col-dense p-px px-2 gap-2 bg-ch-blue-500 bg-opacity-50 hover:bg-opacity-70 rounded-sm"
franknoirot commented 2021-09-12 20:16:28 +02:00 (Migrated from github.com)
Review

Allows the key to appear below (only visually) using CSS order property,

Allows the key to appear below (only visually) using CSS `order` property,
franknoirot commented 2021-09-15 16:19:33 +02:00 (Migrated from github.com)
Review

These comments aren't showing up as out of date which is worrying me @Irev-Dev , so weird. This component was overhauled, see this commit

These comments aren't showing up as out of date which is worrying me @Irev-Dev , so weird. This component was overhauled, see [this commit](https://github.com/Irev-Dev/cadhub/commit/7b2be01430454fb599ec9448de427c19db55e7c5#diff-bbd6cdd539b9e9bc9272aa05cb7894082d87d6772f64ed849ba0385ba960e5a4R29-R35)
id="rename-button"
onClick={onEdit}
>
<Svg
name="check"
franknoirot commented 2021-09-12 20:17:12 +02:00 (Migrated from github.com)
Review

Broke out into its own component to be used across both PartProfile and UserProfile

Broke out into its own component to be used across both `PartProfile` and `UserProfile`
Irev-Dev commented 2021-09-14 13:27:37 +02:00 (Migrated from github.com)
Review

I know you like this component but I kinda hate it, well hate is a sting word but the amount of input params is off putting for such a simple component. If we pulling it out to be reused I might be good to make a few changes.

  • hide should be removed entirely, why did I added it? like should we add a hid param to every component that's conditionally rendered 😩 . Cases where it was being used should just be replaced with `{!shouldHide && <KeyValue ... />}
  • isEditable is a terrible name, The variable is for when the component is in a edit state, but i reads like whether the component is allowed to be edited or something. perhaps 'inEditMode`
  • I liked your variable name hasPermissionToEdit could we rename canEdit to that as well? much clearer.

How does that sound, would you mind?

I know you like this component but I kinda hate it, well hate is a sting word but the amount of input params is off putting for such a simple component. If we pulling it out to be reused I might be good to make a few changes. - hide should be removed entirely, why did I added it? like should we add a hid param to every component that's conditionally rendered 😩 . Cases where it was being used should just be replaced with `{!shouldHide && <KeyValue ... />} - `isEditable` is a terrible name, The variable is for when the component is in a edit state, but i reads like whether the component is allowed to be edited or something. perhaps 'inEditMode` - I liked your variable name `hasPermissionToEdit` could we rename `canEdit` to that as well? much clearer. How does that sound, would you mind?
franknoirot commented 2021-09-15 03:10:09 +02:00 (Migrated from github.com)
Review

Yeah totally, love these ideas. I hear you it about the input params too.

Yeah totally, love these ideas. I hear you it about the input params too.
franknoirot commented 2021-09-15 07:57:54 +02:00 (Migrated from github.com)
Review

I think I found something better with it! Take a look at it.

I think I found something better with it! Take a look at it.
className="w-6 h-6 text-ch-purple-500"
className="w-6 h-6"
strokeWidth={3}
/>
<span>Update</span>

View File

@@ -51,7 +51,7 @@ const ProfileSlashLogin = () => {
<ImageFallback
width={80}
className="rounded-full object-cover"
imageUrl={user?.image}
imageId={user?.image}
/>
)}
</Popover.Button>
@@ -79,10 +79,10 @@ const ProfileSlashLogin = () => {
<div>
<a
href="#"
className="text-indigo-200 font-semibold underline mr-2"
className="text-ch-gray-300 mr-2 px-4 py-2 border-2 border-ch-gray-400 rounded-full hover:bg-ch-gray-600"
onClick={recordedLogin}
>
Sign in/up
Sign In/Up
</a>
</div>
)}

View File

@@ -8,7 +8,7 @@ import { ImageFallback } from '../ImageUploader/ImageUploader'
const ProjectCard = ({ title, mainImage, user, Reaction, cadPackage }) => (
<li
className="rounded p-1.5 bg-ch-gray-760 shadow-ch"
className="rounded p-1.5 bg-ch-gray-760 hover:bg-ch-gray-710 shadow-ch"
key={`${user?.userName}--${title}`}
>
<Link
@@ -33,8 +33,8 @@ const ProjectCard = ({ title, mainImage, user, Reaction, cadPackage }) => (
<div className="flex items-center mt-1">
<div className="w-8 h-8 overflow-hidden rounded-full border border-ch-gray-300 shadow">
<ImageFallback
imageUrl={user?.image}
width={50}
imageId={user?.image} // http://res.cloudinary.com/irevdev/image/upload/c_scale,w_50/v1/CadHub/bc7smqwo9qqmrloyf9xr
width={80} // http://res.cloudinary.com/irevdev/image/upload/c_scale,w_300/v1/CadHub/bc7smqwo9qqmrloyf9xr
/>
</div>
<div className="ml-3 text-lg text-ch-gray-300 font-fira-sans">

View File

@@ -35,7 +35,7 @@ const UserProfile = ({
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
return (
<>
<div className="h-screen flex flex-col text-lg font-fira-sans">
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
<div className="md:h-screen flex flex-col text-lg font-fira-sans">
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
<div className="flex">
<Link
to={routes.home()}
@@ -48,12 +48,15 @@ const UserProfile = ({
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
projectOwner={user?.userName}
projectOwnerImage={user?.image}
projectOwnerId={user?.id}
/>
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
>
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
<span></span>
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
</IdeHeader>
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
</div>
<div className="relative flex-grow h-full">
<div className="grid md:grid-cols-profile-layout grid-flow-row-dense absolute inset-0">
{/* Side panel */}
<section className="bg-ch-gray-760 font-fira-sans px-12 pt-12 overflow-y-auto ch-scrollbar">
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
<section className="bg-ch-gray-760 font-fira-sans p-12 md:overflow-y-auto ch-scrollbar">
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
<div className="flex gap-6">
{!isEditable && (
<div className="w-28 flex-shrink-0">
@@ -98,8 +101,8 @@ const UserProfile = ({
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
</div>
</section>
{/* Viewer */}
<div className="py-10 px-8 w-full min-h-md relative bg-ch-gray-800 overflow-auto ch-scrollbar">
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
<h3 className="text-2xl text-ch-gray-500 mb-4">Projects</h3>
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
<div className="py-10 px-8 w-full h-full relative bg-ch-gray-800 md:overflow-y-auto ch-scrollbar">
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
<h3 className="text-2xl text-ch-gray-500 mb-4 md:hidden">Projects</h3>
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
<ProjectsOfUser userName={user?.userName} />
</div>
</div>
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?
franknoirot commented 2021-09-12 20:18:51 +02:00 (Migrated from github.com)
Review

Initializes values from user state into the config object. Is this a code smell?

Initializes values from `user` state into the config object. Is this a code smell?

View File

@@ -91,7 +91,7 @@ const MainLayout = ({ children, shouldRemoveFooterInIde }) => {
}
}, [hash, client])
return (
<div className="min-h-screen flex flex-col">
<div className="min-h-screen flex flex-col ch-scrollbar">
<header id="cadhub-main-header">
<nav className="flex justify-between h-16 px-4 bg-ch-gray-900">
<ul className="flex items-center">
@@ -140,7 +140,7 @@ const MainLayout = ({ children, shouldRemoveFooterInIde }) => {
<ImageFallback
width={80}
className="rounded-full object-cover"
imageUrl={user?.image}
imageId={user?.image}
/>
)}
</Popover.Button>