format
This commit is contained in:
@@ -76,8 +76,8 @@ function Gooey() {
|
||||
const z = randomSign(Math.random() * 2)
|
||||
const position: [number, number, number] = [x, z, y]
|
||||
const size = Math.random() * 0.8 + 0.1
|
||||
const distort = (size > .1) ? Math.random() * .6 * size + 0.2 : 0
|
||||
const speed = (size > .1) ? (Math.random() * 0.8) / size / size + 0.1 : 0
|
||||
const distort = size > 0.1 ? Math.random() * 0.6 * size + 0.2 : 0
|
||||
const speed = size > 0.1 ? (Math.random() * 0.8) / size / size + 0.1 : 0
|
||||
return { position, size, distort, speed }
|
||||
})
|
||||
const secondSet = Array.from({ length: 5 }).map((_, index) => {
|
||||
@@ -87,8 +87,8 @@ function Gooey() {
|
||||
const z = randomSign(Math.random() * 2)
|
||||
const position: [number, number, number] = [x, z, y]
|
||||
const size = Math.random() * 0.2 + 0.05
|
||||
const distort = (size > .1) ? Math.random() * .8 * size + 0.2 : 0
|
||||
const speed = (size > .1) ? (Math.random() * 0.5) / size / size + 0.1 : 0
|
||||
const distort = size > 0.1 ? Math.random() * 0.8 * size + 0.2 : 0
|
||||
const speed = size > 0.1 ? (Math.random() * 0.5) / size / size + 0.1 : 0
|
||||
return { position, size, distort, speed }
|
||||
})
|
||||
return [...firstSet, ...secondSet]
|
||||
|
||||
@@ -53,13 +53,14 @@ export const sidebarTopConfig: SidebarConfigType[] = [
|
||||
]
|
||||
|
||||
const DiscordLink = () => (
|
||||
<a className="underline text-ch-pink-300"
|
||||
href="https://discord.gg/SD7zFRNjGH"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Discord
|
||||
</a>
|
||||
<a
|
||||
className="underline text-ch-pink-300"
|
||||
href="https://discord.gg/SD7zFRNjGH"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Discord
|
||||
</a>
|
||||
)
|
||||
|
||||
const settingsConfig = [
|
||||
@@ -74,7 +75,8 @@ const settingsConfig = [
|
||||
</p>
|
||||
<hr className="my-2" />
|
||||
<p className="p-2">
|
||||
We're building configuration settings for the Viewer pane now. Join us on <DiscordLink/> if you want to lend a hand!
|
||||
We're building configuration settings for the Viewer pane now. Join us
|
||||
on <DiscordLink /> if you want to lend a hand!
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
@@ -90,7 +92,8 @@ const settingsConfig = [
|
||||
</p>
|
||||
<hr className="my-2" />
|
||||
<p className="p-2">
|
||||
We're building configuration settings for the Viewer pane now. Join us on <DiscordLink/> if you want to lend a hand!
|
||||
We're building configuration settings for the Viewer pane now. Join us
|
||||
on <DiscordLink /> if you want to lend a hand!
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
@@ -106,7 +109,8 @@ const settingsConfig = [
|
||||
</p>
|
||||
<hr className="my-2" />
|
||||
<p className="p-2">
|
||||
We're building configuration settings for the Viewer pane now. Join us on <DiscordLink/> if you want to lend a hand!
|
||||
We're building configuration settings for the Viewer pane now. Join us
|
||||
on <DiscordLink /> if you want to lend a hand!
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
|
||||
@@ -7,24 +7,25 @@ interface EditToggleType {
|
||||
}
|
||||
|
||||
const EditToggle = ({
|
||||
onEdit = () => { console.error('Field declared editable without edit action.') },
|
||||
onEdit = () => {
|
||||
console.error('Field declared editable without edit action.')
|
||||
},
|
||||
isEditing = false,
|
||||
} : EditToggleType) => (
|
||||
(isEditing ? (
|
||||
<button
|
||||
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"
|
||||
id="rename-button"
|
||||
onClick={onEdit}
|
||||
>
|
||||
<Svg name="check" className="w-6 h-6" strokeWidth={3} />
|
||||
<span>Update</span>
|
||||
</button>
|
||||
) : (
|
||||
<button onClick={onEdit}>
|
||||
<Svg name="pencil-solid" className="h-4 w-4 ml-4 mb-2" />
|
||||
</button>
|
||||
))
|
||||
)
|
||||
}: EditToggleType) =>
|
||||
isEditing ? (
|
||||
<button
|
||||
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"
|
||||
id="rename-button"
|
||||
onClick={onEdit}
|
||||
>
|
||||
<Svg name="check" className="w-6 h-6" strokeWidth={3} />
|
||||
<span>Update</span>
|
||||
</button>
|
||||
) : (
|
||||
<button onClick={onEdit}>
|
||||
<Svg name="pencil-solid" className="h-4 w-4 ml-4 mb-2" />
|
||||
</button>
|
||||
)
|
||||
|
||||
interface KeyValueType {
|
||||
keyName: string
|
||||
@@ -51,7 +52,7 @@ const KeyValue = ({
|
||||
}
|
||||
>
|
||||
<span className={edit ? 'text-ch-blue-300' : ''}>{keyName}</span>
|
||||
{edit && edit.hasPermissionToEdit && <EditToggle {...edit} /> }
|
||||
{edit && edit.hasPermissionToEdit && <EditToggle {...edit} />}
|
||||
</div>
|
||||
<div className={'text-ch-gray-300 ' + (bottom ? 'mb-1' : 'mt-1')}>
|
||||
{children}
|
||||
|
||||
@@ -32,10 +32,7 @@ const ProjectCard = ({ title, mainImage, user, Reaction, cadPackage }) => (
|
||||
</div>
|
||||
<div className="flex items-center mt-1">
|
||||
<div className="w-8 h-8 overflow-hidden rounded-full border border-ch-gray-300 shadow">
|
||||
<ImageFallback
|
||||
imageId={user?.image}
|
||||
width={80}
|
||||
/>
|
||||
<ImageFallback imageId={user?.image} width={80} />
|
||||
</div>
|
||||
<div className="ml-3 text-lg text-ch-gray-300 font-fira-sans">
|
||||
<div className="">{title}</div>
|
||||
|
||||
@@ -102,41 +102,43 @@ const ProjectProfile = ({
|
||||
className="px-3 py-2 rounded"
|
||||
/>
|
||||
</div>
|
||||
{ (project?.description || hasPermissionToEdit) && <KeyValue
|
||||
keyName="Description"
|
||||
edit={{
|
||||
hasPermissionToEdit,
|
||||
isEditing,
|
||||
onEdit: () => {
|
||||
if (!isEditing) {
|
||||
setIsEditing(true)
|
||||
} else {
|
||||
onEditSaveClick()
|
||||
setIsEditing(false)
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
<div
|
||||
id="description-wrap"
|
||||
name="description"
|
||||
className={
|
||||
'markdown-overrides rounded-sm pb-2 mt-2' +
|
||||
(isEditing ? ' min-h-md' : '')
|
||||
}
|
||||
onClick={(e) =>
|
||||
e?.target?.id === 'description-wrap' &&
|
||||
editorRef?.current?.focusAtEnd()
|
||||
}
|
||||
{(project?.description || hasPermissionToEdit) && (
|
||||
<KeyValue
|
||||
keyName="Description"
|
||||
edit={{
|
||||
hasPermissionToEdit,
|
||||
isEditing,
|
||||
onEdit: () => {
|
||||
if (!isEditing) {
|
||||
setIsEditing(true)
|
||||
} else {
|
||||
onEditSaveClick()
|
||||
setIsEditing(false)
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Editor
|
||||
ref={editorRef}
|
||||
defaultValue={project?.description || ''}
|
||||
readOnly={!isEditing}
|
||||
onChange={onDescriptionChange}
|
||||
/>
|
||||
</div>
|
||||
</KeyValue> }
|
||||
<div
|
||||
id="description-wrap"
|
||||
name="description"
|
||||
className={
|
||||
'markdown-overrides rounded-sm pb-2 mt-2' +
|
||||
(isEditing ? ' min-h-md' : '')
|
||||
}
|
||||
onClick={(e) =>
|
||||
e?.target?.id === 'description-wrap' &&
|
||||
editorRef?.current?.focusAtEnd()
|
||||
}
|
||||
>
|
||||
<Editor
|
||||
ref={editorRef}
|
||||
defaultValue={project?.description || ''}
|
||||
readOnly={!isEditing}
|
||||
onChange={onDescriptionChange}
|
||||
/>
|
||||
</div>
|
||||
</KeyValue>
|
||||
)}
|
||||
<div className="grid grid-flow-col-dense gap-6">
|
||||
<KeyValue keyName="Created on">
|
||||
{new Date(project?.createdAt).toDateString()}
|
||||
@@ -154,64 +156,68 @@ const ProjectProfile = ({
|
||||
className=""
|
||||
/>
|
||||
</KeyValue>
|
||||
{ currentUser && <KeyValue keyName="Comments">
|
||||
{!isEditing && (
|
||||
<>
|
||||
{currentUser && (
|
||||
<>
|
||||
<div className="pt-1">
|
||||
<textarea
|
||||
className="w-full h-32 rounded shadow-inner outline-none resize-none p-3 bg-ch-gray-600 placeholder-ch-gray-500 font-fira-sans"
|
||||
placeholder="Have a question about this model, or a helpful tip about how to improve it? Remember, be nice!"
|
||||
value={comment}
|
||||
onChange={({ target }) =>
|
||||
setComment(target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className={getActiveClasses(
|
||||
'ml-auto hover:bg-opacity-100 bg-ch-pink-800 bg-opacity-30 mt-4 mb-6 text-ch-gray-300',
|
||||
{ 'bg-indigo-200': currentUser }
|
||||
)}
|
||||
shouldAnimateHover
|
||||
disabled={!currentUser}
|
||||
iconName={''}
|
||||
onClick={onCommentClear}
|
||||
>
|
||||
Comment
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<ul>
|
||||
{project?.Comment.map(
|
||||
({ text, user, id, createdAt }) => (
|
||||
<li key={id} className="mb-5">
|
||||
<div className="flex justify-between">
|
||||
<Link
|
||||
className="flex items-center"
|
||||
to={routes.user({ userName: user?.userName })}
|
||||
>
|
||||
<Gravatar
|
||||
image={user?.image}
|
||||
className="w-10 h-10 mr-4"
|
||||
/>
|
||||
{user?.userName}
|
||||
</Link>
|
||||
<div className="font-fira-code text-ch-blue-400 flex items-center">
|
||||
{new Date(createdAt).toDateString()}
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-5 border-l-2 pl-5 my-3 border-ch-gray-300 text-ch-gray-300">
|
||||
{text}
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
{currentUser && (
|
||||
<KeyValue keyName="Comments">
|
||||
{!isEditing && (
|
||||
<>
|
||||
{currentUser && (
|
||||
<>
|
||||
<div className="pt-1">
|
||||
<textarea
|
||||
className="w-full h-32 rounded shadow-inner outline-none resize-none p-3 bg-ch-gray-600 placeholder-ch-gray-500 font-fira-sans"
|
||||
placeholder="Have a question about this model, or a helpful tip about how to improve it? Remember, be nice!"
|
||||
value={comment}
|
||||
onChange={({ target }) =>
|
||||
setComment(target.value)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
className={getActiveClasses(
|
||||
'ml-auto hover:bg-opacity-100 bg-ch-pink-800 bg-opacity-30 mt-4 mb-6 text-ch-gray-300',
|
||||
{ 'bg-indigo-200': currentUser }
|
||||
)}
|
||||
shouldAnimateHover
|
||||
disabled={!currentUser}
|
||||
iconName={''}
|
||||
onClick={onCommentClear}
|
||||
>
|
||||
Comment
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</KeyValue> }
|
||||
<ul>
|
||||
{project?.Comment.map(
|
||||
({ text, user, id, createdAt }) => (
|
||||
<li key={id} className="mb-5">
|
||||
<div className="flex justify-between">
|
||||
<Link
|
||||
className="flex items-center"
|
||||
to={routes.user({
|
||||
userName: user?.userName,
|
||||
})}
|
||||
>
|
||||
<Gravatar
|
||||
image={user?.image}
|
||||
className="w-10 h-10 mr-4"
|
||||
/>
|
||||
{user?.userName}
|
||||
</Link>
|
||||
<div className="font-fira-code text-ch-blue-400 flex items-center">
|
||||
{new Date(createdAt).toDateString()}
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-5 border-l-2 pl-5 my-3 border-ch-gray-300 text-ch-gray-300">
|
||||
{text}
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</KeyValue>
|
||||
)}
|
||||
{hasPermissionToEdit && (
|
||||
<>
|
||||
<h4 className="mt-10 text-red-600">Danger Zone</h4>
|
||||
|
||||
@@ -13,15 +13,18 @@ import {
|
||||
|
||||
// This function initializes the state management object for each of the fields
|
||||
function buildFieldsConfig(fieldsConfig, user, hasPermissionToEdit) {
|
||||
return Object.fromEntries(Object.keys(fieldsConfig).map(
|
||||
(key: string): [string, FieldType] => ([key, {
|
||||
name: key,
|
||||
currentValue: user[key],
|
||||
newValue: user[key],
|
||||
isEditing: false,
|
||||
hasPermissionToEdit,
|
||||
}])
|
||||
))
|
||||
return Object.fromEntries(
|
||||
Object.keys(fieldsConfig).map((key: string): [string, FieldType] => [
|
||||
key,
|
||||
{
|
||||
name: key,
|
||||
currentValue: user[key],
|
||||
newValue: user[key],
|
||||
isEditing: false,
|
||||
hasPermissionToEdit,
|
||||
},
|
||||
])
|
||||
)
|
||||
}
|
||||
|
||||
const UserProfile = ({
|
||||
@@ -39,7 +42,11 @@ const UserProfile = ({
|
||||
navigate(routes.user({ userName: user.userName }))
|
||||
}, [currentUser])
|
||||
|
||||
const initializedFields = buildFieldsConfig(fieldComponents, user, hasPermissionToEdit)
|
||||
const initializedFields = buildFieldsConfig(
|
||||
fieldComponents,
|
||||
user,
|
||||
hasPermissionToEdit
|
||||
)
|
||||
const [fields, fieldDispatch] = useReducer(fieldReducer, initializedFields)
|
||||
const {
|
||||
name: NameField,
|
||||
|
||||
@@ -51,29 +51,32 @@ const ProfileKeyValue = ({
|
||||
hasPermissionToEdit,
|
||||
children,
|
||||
bottom = false,
|
||||
} : ProfileKeyValueType) => {
|
||||
}: ProfileKeyValueType) => {
|
||||
return (
|
||||
(user[field.name] && hasPermissionToEdit) && <KeyValue
|
||||
keyName={field.name}
|
||||
edit={{
|
||||
hasPermissionToEdit,
|
||||
isEditing: field.isEditing,
|
||||
onEdit: () => {
|
||||
if (field.isEditing && field.currentValue !== field.newValue) {
|
||||
save(user.userName, { [field.name]: field.newValue })
|
||||
}
|
||||
dispatch({
|
||||
type: 'SET_CURRENT_VALUE',
|
||||
payload: { field: field.name, value: field.newValue },
|
||||
})
|
||||
dispatch({ type: 'TOGGLE_EDITING', payload: field.name })
|
||||
},
|
||||
}}
|
||||
bottom={bottom}
|
||||
className="mb-4"
|
||||
>
|
||||
{children}
|
||||
</KeyValue>
|
||||
user[field.name] &&
|
||||
hasPermissionToEdit && (
|
||||
<KeyValue
|
||||
keyName={field.name}
|
||||
edit={{
|
||||
hasPermissionToEdit,
|
||||
isEditing: field.isEditing,
|
||||
onEdit: () => {
|
||||
if (field.isEditing && field.currentValue !== field.newValue) {
|
||||
save(user.userName, { [field.name]: field.newValue })
|
||||
}
|
||||
dispatch({
|
||||
type: 'SET_CURRENT_VALUE',
|
||||
payload: { field: field.name, value: field.newValue },
|
||||
})
|
||||
dispatch({ type: 'TOGGLE_EDITING', payload: field.name })
|
||||
},
|
||||
}}
|
||||
bottom={bottom}
|
||||
className="mb-4"
|
||||
>
|
||||
{children}
|
||||
</KeyValue>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -110,7 +113,7 @@ function BioField(props) {
|
||||
)
|
||||
}
|
||||
|
||||
function MemberSinceField(props : FieldComponentPropsType) {
|
||||
function MemberSinceField(props: FieldComponentPropsType) {
|
||||
return (
|
||||
<KeyValue keyName="Member Since">
|
||||
<p className="text-ch-gray-300">
|
||||
@@ -120,7 +123,7 @@ function MemberSinceField(props : FieldComponentPropsType) {
|
||||
)
|
||||
}
|
||||
|
||||
function ImageField(props : FieldComponentPropsType) {
|
||||
function ImageField(props: FieldComponentPropsType) {
|
||||
const { field, user, save, hasPermissionToEdit } = props
|
||||
return (
|
||||
<ImageUploader
|
||||
@@ -138,7 +141,7 @@ function ImageField(props : FieldComponentPropsType) {
|
||||
)
|
||||
}
|
||||
|
||||
function NameField(props : FieldComponentPropsType) {
|
||||
function NameField(props: FieldComponentPropsType) {
|
||||
const { user, dispatch, field } = props
|
||||
|
||||
return (
|
||||
@@ -162,7 +165,7 @@ function NameField(props : FieldComponentPropsType) {
|
||||
)
|
||||
}
|
||||
|
||||
function UserNameField(props : FieldComponentPropsType) {
|
||||
function UserNameField(props: FieldComponentPropsType) {
|
||||
const { dispatch, field } = props
|
||||
|
||||
return (
|
||||
@@ -196,7 +199,8 @@ export function fieldReducer(state, action) {
|
||||
[action.payload]: {
|
||||
...state[action.payload],
|
||||
isEditing:
|
||||
state[action.payload].hasPermissionToEdit && !state[action.payload].isEditing
|
||||
state[action.payload].hasPermissionToEdit &&
|
||||
!state[action.payload].isEditing
|
||||
? true
|
||||
: false,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user