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