Update Userpic component (#160)
This commit is contained in:
parent
c95907968c
commit
f9c30a99cf
|
@ -4,7 +4,7 @@ import { getPagePath } from '@nanostores/router'
|
|||
|
||||
import MD from './MD'
|
||||
import { AuthorCard } from '../Author/AuthorCard'
|
||||
import Userpic from '../Author/Userpic'
|
||||
import { Userpic } from '../Author/Userpic'
|
||||
import { CommentRatingControl } from './CommentRatingControl'
|
||||
import { CommentDate } from './CommentDate'
|
||||
import { ShowIfAuthenticated } from '../_shared/ShowIfAuthenticated'
|
||||
|
@ -123,7 +123,8 @@ export const Comment = (props: Props) => {
|
|||
fallback={
|
||||
<div>
|
||||
<Userpic
|
||||
user={comment().createdBy as Author}
|
||||
name={comment().createdBy.name}
|
||||
userpic={comment().createdBy.userpic}
|
||||
isBig={false}
|
||||
class={clsx({
|
||||
[styles.compactUserpic]: props.compact
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { Author } from '../../graphql/types.gen'
|
||||
import Userpic from './Userpic'
|
||||
import { Userpic } from './Userpic'
|
||||
import { Icon } from '../_shared/Icon'
|
||||
import styles from './AuthorCard.module.scss'
|
||||
import { createMemo, createSignal, For, Show } from 'solid-js'
|
||||
|
@ -101,7 +101,8 @@ export const AuthorCard = (props: AuthorCardProps) => {
|
|||
}}
|
||||
>
|
||||
<Userpic
|
||||
user={props.author}
|
||||
name={props.author.name}
|
||||
userpic={props.author.userpic}
|
||||
hasLink={props.hasLink}
|
||||
isBig={props.isAuthorPage}
|
||||
isAuthorsList={props.isAuthorsList}
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
import { Show } from 'solid-js'
|
||||
import type { Author, User } from '../../graphql/types.gen'
|
||||
import styles from './Userpic.module.scss'
|
||||
import { clsx } from 'clsx'
|
||||
|
||||
interface UserpicProps {
|
||||
user: Author | User
|
||||
hasLink?: boolean
|
||||
isBig?: boolean
|
||||
class?: string
|
||||
isAuthorsList?: boolean
|
||||
isFeedMode?: boolean
|
||||
}
|
||||
|
||||
export default (props: UserpicProps) => {
|
||||
const letters = () => {
|
||||
const names = props.user && props.user.name ? props.user.name.split(' ') : []
|
||||
|
||||
return names[0][0] + (names.length > 1 ? names[1][0] : '')
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
class={clsx(styles.circlewrap, props.class)}
|
||||
classList={{
|
||||
[styles.big]: props.isBig,
|
||||
[styles.authorsList]: props.isAuthorsList,
|
||||
[styles.feedMode]: props.isFeedMode
|
||||
}}
|
||||
>
|
||||
<Show when={props.hasLink}>
|
||||
<a href={`/author/${props.user.slug}`}>
|
||||
<Show
|
||||
when={props.user && props.user.userpic === ''}
|
||||
fallback={
|
||||
<img
|
||||
src={props.user.userpic || '/icons/user-default.svg'}
|
||||
alt={props.user.name || ''}
|
||||
classList={{ [styles.anonymous]: !props.user.userpic }}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div class={styles.userpic}>{letters()}</div>
|
||||
</Show>
|
||||
</a>
|
||||
</Show>
|
||||
|
||||
<Show when={!props.hasLink}>
|
||||
<Show
|
||||
when={props.user && props.user.userpic === ''}
|
||||
fallback={
|
||||
<img
|
||||
src={props.user.userpic || '/icons/user-default.svg'}
|
||||
alt={props.user.name || ''}
|
||||
classList={{ [styles.anonymous]: !props.user.userpic }}
|
||||
loading="lazy"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div class={styles.userpic}>{letters()}</div>
|
||||
</Show>
|
||||
</Show>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
.circlewrap {
|
||||
.Userpic {
|
||||
align-items: baseline;
|
||||
background: #f7f7f8;
|
||||
border-radius: 100%;
|
||||
|
@ -19,7 +19,7 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
.userpic {
|
||||
.letters {
|
||||
background-color: white;
|
||||
border-radius: 50%;
|
||||
border: 1.5px solid black;
|
||||
|
@ -53,24 +53,24 @@
|
|||
color: #000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.big.circlewrap {
|
||||
margin-right: 0;
|
||||
max-width: 168px;
|
||||
min-width: 168px;
|
||||
height: 168px;
|
||||
width: 168px;
|
||||
&.big {
|
||||
margin-right: 0;
|
||||
max-width: 168px;
|
||||
min-width: 168px;
|
||||
height: 168px;
|
||||
width: 168px;
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
margin-right: 4.8rem;
|
||||
}
|
||||
@include media-breakpoint-up(md) {
|
||||
margin-right: 4.8rem;
|
||||
}
|
||||
|
||||
.userpic {
|
||||
font-size: 2em;
|
||||
line-height: 168px;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
.letters {
|
||||
font-size: 2em;
|
||||
line-height: 168px;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,16 +81,20 @@
|
|||
height: 6.8rem;
|
||||
width: 6.8rem;
|
||||
|
||||
.userpic {
|
||||
.letters {
|
||||
line-height: 6.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.feedMode {
|
||||
.userpic {
|
||||
.letters {
|
||||
font-size: 0.8rem;
|
||||
line-height: 14px;
|
||||
min-width: 16px;
|
||||
max-width: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.cursorPointer {
|
||||
cursor: pointer;
|
||||
}
|
62
src/components/Author/Userpic/Userpic.tsx
Normal file
62
src/components/Author/Userpic/Userpic.tsx
Normal file
|
@ -0,0 +1,62 @@
|
|||
import { Show } from 'solid-js'
|
||||
import type { Author, User } from '../../../graphql/types.gen'
|
||||
import styles from './Userpic.module.scss'
|
||||
import { clsx } from 'clsx'
|
||||
import { imageProxy } from '../../../utils/imageProxy'
|
||||
import { ConditionalWrapper } from '../../_shared/ConditionalWrapper'
|
||||
import { Loading } from '../../_shared/Loading'
|
||||
|
||||
type Props = {
|
||||
name: string
|
||||
userpic: string
|
||||
class?: string
|
||||
slug?: string
|
||||
onClick?: () => void
|
||||
loading?: boolean
|
||||
isBig?: boolean
|
||||
hasLink?: boolean
|
||||
|
||||
isAuthorsList?: boolean
|
||||
isFeedMode?: boolean
|
||||
}
|
||||
|
||||
export const Userpic = (props: Props) => {
|
||||
const letters = () => {
|
||||
if (!props.name) return
|
||||
const names = props.name ? props.name.split(' ') : []
|
||||
return names[0][0] + (names.length > 1 ? names[1][0] : '')
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
class={clsx(styles.Userpic, props.class, {
|
||||
[styles.big]: props.isBig,
|
||||
[styles.authorsList]: props.isAuthorsList,
|
||||
[styles.feedMode]: props.isFeedMode,
|
||||
[styles.cursorPointer]: props.onClick
|
||||
})}
|
||||
onClick={props.onClick}
|
||||
>
|
||||
<Show when={!props.loading} fallback={<Loading />}>
|
||||
<ConditionalWrapper
|
||||
condition={props.hasLink}
|
||||
wrapper={(children) => <a href={`/author/${props.slug}`}>{children}</a>}
|
||||
>
|
||||
<Show
|
||||
when={!props.userpic}
|
||||
fallback={
|
||||
<img
|
||||
class={clsx({ [styles.anonymous]: !props.userpic })}
|
||||
src={imageProxy(props.userpic) || '/icons/user-default.svg'}
|
||||
alt={props.name || ''}
|
||||
loading="lazy"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div class={styles.letters}>{letters()}</div>
|
||||
</Show>
|
||||
</ConditionalWrapper>
|
||||
</Show>
|
||||
</div>
|
||||
)
|
||||
}
|
1
src/components/Author/Userpic/index.ts
Normal file
1
src/components/Author/Userpic/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { Userpic } from './Userpic'
|
|
@ -9,7 +9,7 @@ import { useSession } from '../../../context/session'
|
|||
import { useLocalize } from '../../../context/localize'
|
||||
import styles from './Sidebar.module.scss'
|
||||
import { clsx } from 'clsx'
|
||||
import Userpic from '../../Author/Userpic'
|
||||
import { Userpic } from '../../Author/Userpic'
|
||||
import { getPagePath } from '@nanostores/router'
|
||||
import { router, useRouter } from '../../../stores/router'
|
||||
|
||||
|
@ -138,7 +138,10 @@ export const Sidebar = (props: FeedSidebarProps) => {
|
|||
>
|
||||
<div class={styles.sidebarItemName}>
|
||||
<Show when={authorEntities()[authorSlug]}>
|
||||
<Userpic user={authorEntities()[authorSlug]} />
|
||||
<Userpic
|
||||
name={authorEntities()[authorSlug].name}
|
||||
userpic={authorEntities()[authorSlug].userpic}
|
||||
/>
|
||||
</Show>
|
||||
<Show when={!authorEntities()[authorSlug]}>
|
||||
<Icon name="hash" class={styles.icon} />
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Icon } from '../_shared/Icon'
|
|||
import { createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js'
|
||||
import Notifications from './Notifications'
|
||||
import { ProfilePopup } from './ProfilePopup'
|
||||
import Userpic from '../Author/Userpic'
|
||||
import { Userpic } from '../Author/Userpic'
|
||||
import { showModal, useWarningsStore } from '../../stores/ui'
|
||||
import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient'
|
||||
import { useSession } from '../../context/session'
|
||||
|
@ -216,7 +216,11 @@ export const HeaderAuth = (props: Props) => {
|
|||
<div class={styles.userControlItem}>
|
||||
<button class={styles.button}>
|
||||
<div classList={{ entered: page().path === `/${session().user?.slug}` }}>
|
||||
<Userpic user={session().user} class={styles.userpic} />
|
||||
<Userpic
|
||||
name={session().user.name}
|
||||
userpic={session().user.userpic}
|
||||
class={styles.userpic}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -12,7 +12,7 @@ import { splitToPages } from '../../../utils/splitToPages'
|
|||
import styles from './Author.module.scss'
|
||||
import stylesArticle from '../../Article/Article.module.scss'
|
||||
import { clsx } from 'clsx'
|
||||
import Userpic from '../../Author/Userpic'
|
||||
import { Userpic } from '../../Author/Userpic'
|
||||
import { Popup } from '../../_shared/Popup'
|
||||
import { AuthorCard } from '../../Author/AuthorCard'
|
||||
import { apiClient } from '../../../utils/apiClient'
|
||||
|
@ -178,12 +178,12 @@ export const AuthorView = (props: AuthorProps) => {
|
|||
<Switch>
|
||||
<Match when={followers().length <= 3}>
|
||||
<For each={followers().slice(0, 3)}>
|
||||
{(f) => <Userpic user={f} class={styles.userpic} />}
|
||||
{(f) => <Userpic name={f.name} userpic={f.userpic} class={styles.userpic} />}
|
||||
</For>
|
||||
</Match>
|
||||
<Match when={followers().length > 3}>
|
||||
<For each={followers().slice(0, 2)}>
|
||||
{(f) => <Userpic user={f} class={styles.userpic} />}
|
||||
{(f) => <Userpic name={f.name} userpic={f.userpic} class={styles.userpic} />}
|
||||
</For>
|
||||
<div class={clsx(styles.userpic, styles.subscribersCounter)}>
|
||||
{followers().length}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import { JSX } from 'solid-js'
|
||||
|
||||
type Props = {
|
||||
condition: boolean
|
||||
wrapper: (children: JSX.Element) => JSX.Element
|
||||
children: JSX.Element
|
||||
}
|
||||
|
||||
export const ConditionalWrapper = (props: Props) => {
|
||||
return props.condition ? props.wrapper(props.children) : props.children
|
||||
}
|
1
src/components/_shared/ConditionalWrapper/index.ts
Normal file
1
src/components/_shared/ConditionalWrapper/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { ConditionalWrapper } from './ConditionalWrapper'
|
|
@ -1,7 +1,7 @@
|
|||
import type { Reaction } from '../../../graphql/types.gen'
|
||||
import { Author, ReactionKind } from '../../../graphql/types.gen'
|
||||
import { For, Show } from 'solid-js'
|
||||
import Userpic from '../../Author/Userpic'
|
||||
import type { Reaction } from '../../../graphql/types.gen'
|
||||
import { ReactionKind } from '../../../graphql/types.gen'
|
||||
import { Userpic } from '../../Author/Userpic'
|
||||
import styles from './VotersList.module.scss'
|
||||
import { clsx } from 'clsx'
|
||||
|
||||
|
@ -22,7 +22,12 @@ export const VotersList = (props: Props) => {
|
|||
{(reaction) => (
|
||||
<li class={styles.item}>
|
||||
<div class={styles.user}>
|
||||
<Userpic user={reaction.createdBy as Author} isBig={false} isAuthorsList={false} />
|
||||
<Userpic
|
||||
name={reaction.createdBy.name}
|
||||
userpic={reaction.createdBy.userpic}
|
||||
isBig={false}
|
||||
isAuthorsList={false}
|
||||
/>
|
||||
<a href={`/author/${reaction.createdBy.slug}`}>{reaction.createdBy.name || ''}</a>
|
||||
</div>
|
||||
{reaction.kind === ReactionKind.Like ? (
|
||||
|
|
|
@ -13,34 +13,6 @@ h5 {
|
|||
margin: 0 0 0.8rem;
|
||||
}
|
||||
|
||||
.avatarContainer {
|
||||
border-radius: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 18rem;
|
||||
width: 18rem;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
height: 100%;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
background: #ccc;
|
||||
border: none;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.avatarInput {
|
||||
border-radius: 100%;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.multipleControls {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
|
|
@ -7,13 +7,12 @@ import styles from './Settings.module.scss'
|
|||
import { useProfileForm } from '../../context/profile'
|
||||
import { validateUrl } from '../../utils/validateUrl'
|
||||
import { createFileUploader } from '@solid-primitives/upload'
|
||||
import { Loading } from '../../components/_shared/Loading'
|
||||
import { useSession } from '../../context/session'
|
||||
import { Button } from '../../components/_shared/Button'
|
||||
import { useSnackbar } from '../../context/snackbar'
|
||||
import { useLocalize } from '../../context/localize'
|
||||
import { Image } from '../../components/_shared/Image'
|
||||
import { handleFileUpload } from '../../utils/handleFileUpload'
|
||||
import { Userpic } from '../../components/Author/Userpic'
|
||||
|
||||
export const ProfileSettingsPage = () => {
|
||||
const { t } = useLocalize()
|
||||
|
@ -72,6 +71,8 @@ export const ProfileSettingsPage = () => {
|
|||
|
||||
const [hostname, setHostname] = createSignal<string | null>(null)
|
||||
onMount(() => setHostname(window?.location.host))
|
||||
|
||||
console.log('!!! form:', form)
|
||||
return (
|
||||
<PageLayout>
|
||||
<Show when={form}>
|
||||
|
@ -90,16 +91,13 @@ export const ProfileSettingsPage = () => {
|
|||
<form onSubmit={handleSubmit} enctype="multipart/form-data">
|
||||
<h4>{t('Userpic')}</h4>
|
||||
<div class="pretty-form__item">
|
||||
<div class={styles.avatarContainer}>
|
||||
<Show when={!isUserpicUpdating()} fallback={<Loading />}>
|
||||
<Image
|
||||
class={styles.avatar}
|
||||
src={form.userpic}
|
||||
alt={form.name}
|
||||
onClick={handleAvatarClick}
|
||||
/>
|
||||
</Show>
|
||||
</div>
|
||||
<Userpic
|
||||
name={form.name}
|
||||
userpic={form.userpic}
|
||||
isBig={true}
|
||||
onClick={handleAvatarClick}
|
||||
loading={isUserpicUpdating()}
|
||||
/>
|
||||
</div>
|
||||
<h4>{t('Name')}</h4>
|
||||
<p class="description">
|
||||
|
|
Loading…
Reference in New Issue
Block a user