parent
5d116ede22
commit
9c7f6249a4
|
@ -19,7 +19,7 @@ import { TopicCard } from '../../Topic/Card'
|
||||||
import { getNumeralsDeclension } from '../../../utils/getNumeralsDeclension'
|
import { getNumeralsDeclension } from '../../../utils/getNumeralsDeclension'
|
||||||
|
|
||||||
type SubscriptionFilter = 'all' | 'users' | 'topics'
|
type SubscriptionFilter = 'all' | 'users' | 'topics'
|
||||||
type AuthorCardProps = {
|
type Props = {
|
||||||
caption?: string
|
caption?: string
|
||||||
hideWriteButton?: boolean
|
hideWriteButton?: boolean
|
||||||
hideDescription?: boolean
|
hideDescription?: boolean
|
||||||
|
@ -46,7 +46,7 @@ function isAuthor(value: Author | Topic): value is Author {
|
||||||
return 'name' in value
|
return 'name' in value
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AuthorCard = (props: AuthorCardProps) => {
|
export const AuthorCard = (props: Props) => {
|
||||||
const { t, lang } = useLocalize()
|
const { t, lang } = useLocalize()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -58,6 +58,7 @@ export const AuthorCard = (props: AuthorCardProps) => {
|
||||||
const [isSubscribing, setIsSubscribing] = createSignal(false)
|
const [isSubscribing, setIsSubscribing] = createSignal(false)
|
||||||
const [subscriptions, setSubscriptions] = createSignal<Array<Author | Topic>>(props.subscriptions)
|
const [subscriptions, setSubscriptions] = createSignal<Array<Author | Topic>>(props.subscriptions)
|
||||||
const [subscriptionFilter, setSubscriptionFilter] = createSignal<SubscriptionFilter>('all')
|
const [subscriptionFilter, setSubscriptionFilter] = createSignal<SubscriptionFilter>('all')
|
||||||
|
const [userpicUrl, setUserpicUrl] = createSignal<string>()
|
||||||
|
|
||||||
const subscribed = createMemo<boolean>(() => {
|
const subscribed = createMemo<boolean>(() => {
|
||||||
return session()?.news?.authors?.some((u) => u === props.author.slug) || false
|
return session()?.news?.authors?.some((u) => u === props.author.slug) || false
|
||||||
|
@ -115,6 +116,10 @@ export const AuthorCard = (props: AuthorCardProps) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (props.isAuthorPage && props.author.userpic.includes('assets.discours.io')) {
|
||||||
|
setUserpicUrl(props.author.userpic.replace('100x', '500x500'))
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
|
@ -145,7 +150,7 @@ export const AuthorCard = (props: AuthorCardProps) => {
|
||||||
<div class="col-md-5">
|
<div class="col-md-5">
|
||||||
<Userpic
|
<Userpic
|
||||||
name={props.author.name}
|
name={props.author.name}
|
||||||
userpic={props.author.userpic}
|
userpic={userpicUrl()}
|
||||||
hasLink={props.hasLink}
|
hasLink={props.hasLink}
|
||||||
isBig={props.isAuthorPage}
|
isBig={props.isAuthorPage}
|
||||||
isAuthorsList={props.isAuthorsList}
|
isAuthorsList={props.isAuthorsList}
|
||||||
|
|
|
@ -220,8 +220,8 @@ const SimplifiedEditor = (props: Props) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
onCleanup(() => {
|
onCleanup(() => {
|
||||||
editor().destroy()
|
|
||||||
window.removeEventListener('keydown', handleKeyDown)
|
window.removeEventListener('keydown', handleKeyDown)
|
||||||
|
editor().destroy()
|
||||||
})
|
})
|
||||||
|
|
||||||
if (props.onChange) {
|
if (props.onChange) {
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { useLocalize } from '../../../context/localize'
|
||||||
import { AuthorRatingControl } from '../../Author/AuthorRatingControl'
|
import { AuthorRatingControl } from '../../Author/AuthorRatingControl'
|
||||||
import { hideModal } from '../../../stores/ui'
|
import { hideModal } from '../../../stores/ui'
|
||||||
|
|
||||||
type AuthorProps = {
|
type Props = {
|
||||||
shouts: Shout[]
|
shouts: Shout[]
|
||||||
author: Author
|
author: Author
|
||||||
authorSlug: string
|
authorSlug: string
|
||||||
|
@ -31,7 +31,7 @@ export type AuthorPageSearchParams = {
|
||||||
export const PRERENDERED_ARTICLES_COUNT = 12
|
export const PRERENDERED_ARTICLES_COUNT = 12
|
||||||
const LOAD_MORE_PAGE_SIZE = 9
|
const LOAD_MORE_PAGE_SIZE = 9
|
||||||
|
|
||||||
export const AuthorView = (props: AuthorProps) => {
|
export const AuthorView = (props: Props) => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
const { sortedArticles } = useArticlesStore({ shouts: props.shouts })
|
const { sortedArticles } = useArticlesStore({ shouts: props.shouts })
|
||||||
const { searchParams, changeSearchParam } = useRouter<AuthorPageSearchParams>()
|
const { searchParams, changeSearchParam } = useRouter<AuthorPageSearchParams>()
|
||||||
|
@ -127,6 +127,7 @@ export const AuthorView = (props: AuthorProps) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={styles.authorPage}>
|
<div class={styles.authorPage}>
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import styles from './GrowingTextarea.module.scss'
|
import styles from './GrowingTextarea.module.scss'
|
||||||
import { createSignal, Show } from 'solid-js'
|
import { createEffect, createSignal, onMount, Show } from 'solid-js'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
class?: string
|
class?: string
|
||||||
|
@ -15,8 +15,16 @@ type Props = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GrowingTextarea = (props: Props) => {
|
export const GrowingTextarea = (props: Props) => {
|
||||||
const [value, setValue] = createSignal<string>(props.initialValue ?? '')
|
const [value, setValue] = createSignal<string>()
|
||||||
const [isFocused, setIsFocused] = createSignal(false)
|
const [isFocused, setIsFocused] = createSignal(false)
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (props.maxLength && props.initialValue?.length > props.maxLength) {
|
||||||
|
setValue(props.initialValue.slice(0, props.maxLength))
|
||||||
|
} else {
|
||||||
|
setValue(props.initialValue ?? '')
|
||||||
|
}
|
||||||
|
})
|
||||||
const handleChangeValue = (event) => {
|
const handleChangeValue = (event) => {
|
||||||
setValue(event.target.value)
|
setValue(event.target.value)
|
||||||
}
|
}
|
||||||
|
@ -32,43 +40,45 @@ export const GrowingTextarea = (props: Props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<Show when={value()}>
|
||||||
class={clsx(styles.GrowingTextarea, {
|
<div
|
||||||
[styles.bordered]: props.variant === 'bordered',
|
class={clsx(styles.GrowingTextarea, {
|
||||||
[styles.hasFieldName]: props.fieldName && value().length > 0
|
[styles.bordered]: props.variant === 'bordered',
|
||||||
})}
|
[styles.hasFieldName]: props.fieldName && value().length > 0
|
||||||
>
|
})}
|
||||||
<Show when={props.fieldName && value().length > 0}>
|
>
|
||||||
<div class={styles.fieldName}>{props.fieldName}</div>
|
<Show when={props.fieldName && value().length > 0}>
|
||||||
</Show>
|
<div class={styles.fieldName}>{props.fieldName}</div>
|
||||||
<div class={clsx(styles.growWrap, props.class)} data-replicated-value={value()}>
|
</Show>
|
||||||
<textarea
|
<div class={clsx(styles.growWrap, props.class)} data-replicated-value={value()}>
|
||||||
ref={props.textAreaRef}
|
<textarea
|
||||||
rows={1}
|
ref={props.textAreaRef}
|
||||||
maxlength={props.maxLength}
|
rows={1}
|
||||||
autocomplete="off"
|
maxlength={props.maxLength}
|
||||||
class={clsx(styles.textInput, props.class)}
|
autocomplete="off"
|
||||||
value={props.initialValue}
|
class={clsx(styles.textInput, props.class)}
|
||||||
onKeyDown={props.allowEnterKey ? handleKeyDown : null}
|
value={props.maxLength ? props.initialValue.slice(0, props.maxLength) : props.initialValue}
|
||||||
onInput={(event) => handleChangeValue(event)}
|
onKeyDown={props.allowEnterKey ? handleKeyDown : null}
|
||||||
onChange={(event) => props.value(event.target.value)}
|
onInput={(event) => handleChangeValue(event)}
|
||||||
placeholder={props.placeholder}
|
onChange={(event) => props.value(event.target.value)}
|
||||||
onFocus={() => setIsFocused(true)}
|
placeholder={props.placeholder}
|
||||||
onBlur={() => setIsFocused(false)}
|
onFocus={() => setIsFocused(true)}
|
||||||
/>
|
onBlur={() => setIsFocused(false)}
|
||||||
</div>
|
/>
|
||||||
<Show when={(props.maxLength && value() && isFocused()) || props.variant === 'bordered'}>
|
|
||||||
<div
|
|
||||||
class={clsx(styles.maxLength, {
|
|
||||||
[styles.visible]: isFocused(),
|
|
||||||
[styles.limited]: value().length === props.maxLength
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
<Show when={props.variant === 'bordered'} fallback={`${value().length} / ${props.maxLength}`}>
|
|
||||||
{`${props.maxLength - value().length}`}
|
|
||||||
</Show>
|
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
<Show when={(props.maxLength && value() && isFocused()) || props.variant === 'bordered'}>
|
||||||
</div>
|
<div
|
||||||
|
class={clsx(styles.maxLength, {
|
||||||
|
[styles.visible]: isFocused(),
|
||||||
|
[styles.limited]: value().length === props.maxLength
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Show when={props.variant === 'bordered'} fallback={`${value().length} / ${props.maxLength}`}>
|
||||||
|
{`${props.maxLength - value().length}`}
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ const useProfileForm = () => {
|
||||||
slug: currentAuthor()?.slug,
|
slug: currentAuthor()?.slug,
|
||||||
bio: currentAuthor()?.bio,
|
bio: currentAuthor()?.bio,
|
||||||
about: currentAuthor()?.about,
|
about: currentAuthor()?.about,
|
||||||
userpic: currentAuthor()?.userpic,
|
userpic: currentAuthor()?.userpic.replace('100x', '500x500'),
|
||||||
links: currentAuthor()?.links
|
links: currentAuthor()?.links
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { PageLayout } from '../../components/_shared/PageLayout'
|
import { PageLayout } from '../../components/_shared/PageLayout'
|
||||||
import { Icon } from '../../components/_shared/Icon'
|
import { Icon } from '../../components/_shared/Icon'
|
||||||
import ProfileSettingsNavigation from '../../components/Discours/ProfileSettingsNavigation'
|
import ProfileSettingsNavigation from '../../components/Discours/ProfileSettingsNavigation'
|
||||||
import { For, createSignal, Show, onMount, onCleanup } from 'solid-js'
|
import { For, createSignal, Show, onMount, onCleanup, createEffect, on } from 'solid-js'
|
||||||
import deepEqual from 'fast-deep-equal'
|
import deepEqual from 'fast-deep-equal'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import styles from './Settings.module.scss'
|
import styles from './Settings.module.scss'
|
||||||
|
@ -16,6 +16,9 @@ import { handleFileUpload } from '../../utils/handleFileUpload'
|
||||||
import { Userpic } from '../../components/Author/Userpic'
|
import { Userpic } from '../../components/Author/Userpic'
|
||||||
import { createStore } from 'solid-js/store'
|
import { createStore } from 'solid-js/store'
|
||||||
import { clone } from '../../utils/clone'
|
import { clone } from '../../utils/clone'
|
||||||
|
import SimplifiedEditor from '../../components/Editor/SimplifiedEditor'
|
||||||
|
import { GrowingTextarea } from '../../components/_shared/GrowingTextarea'
|
||||||
|
import { resetSortedArticles } from '../../stores/zine/articles'
|
||||||
|
|
||||||
export const ProfileSettingsPage = () => {
|
export const ProfileSettingsPage = () => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
|
@ -96,6 +99,12 @@ export const ProfileSettingsPage = () => {
|
||||||
setPrevForm(clone(form))
|
setPrevForm(clone(form))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (!deepEqual(form, prevForm)) {
|
||||||
|
setIsFloatingPanelVisible(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Show when={form}>
|
<Show when={form}>
|
||||||
|
@ -111,15 +120,7 @@ export const ProfileSettingsPage = () => {
|
||||||
<div class="col-md-20 col-lg-18 col-xl-16">
|
<div class="col-md-20 col-lg-18 col-xl-16">
|
||||||
<h1>{t('Profile settings')}</h1>
|
<h1>{t('Profile settings')}</h1>
|
||||||
<p class="description">{t('Here you can customize your profile the way you want.')}</p>
|
<p class="description">{t('Here you can customize your profile the way you want.')}</p>
|
||||||
<form
|
<form onSubmit={handleSubmit} enctype="multipart/form-data">
|
||||||
onSubmit={handleSubmit}
|
|
||||||
onChange={() => {
|
|
||||||
if (!deepEqual(form, prevForm)) {
|
|
||||||
setIsFloatingPanelVisible(true)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
enctype="multipart/form-data"
|
|
||||||
>
|
|
||||||
<h4>{t('Userpic')}</h4>
|
<h4>{t('Userpic')}</h4>
|
||||||
<div class="pretty-form__item">
|
<div class="pretty-form__item">
|
||||||
<Userpic
|
<Userpic
|
||||||
|
@ -169,29 +170,26 @@ export const ProfileSettingsPage = () => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4>{t('Introduce')}</h4>
|
<h4>{t('Introduce')}</h4>
|
||||||
<div class="pretty-form__item">
|
<GrowingTextarea
|
||||||
<textarea
|
variant="bordered"
|
||||||
name="bio"
|
placeholder={t('Introduce')}
|
||||||
id="bio"
|
value={(value) => updateFormField('bio', value)}
|
||||||
placeholder={t('Introduce')}
|
initialValue={form.bio}
|
||||||
value={form.bio}
|
allowEnterKey={false}
|
||||||
onChange={(event) => updateFormField('bio', event.currentTarget.value)}
|
maxLength={80}
|
||||||
/>
|
/>
|
||||||
<label for="presentation">{t('Introduce')}</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h4>{t('About myself')}</h4>
|
<h4>{t('About myself')}</h4>
|
||||||
<div class="pretty-form__item">
|
<SimplifiedEditor
|
||||||
<textarea
|
variant="bordered"
|
||||||
name="about"
|
onlyBubbleControls={true}
|
||||||
id="about"
|
smallHeight={true}
|
||||||
placeholder={t('About myself')}
|
placeholder={t('About myself')}
|
||||||
value={form.about}
|
label={t('About myself')}
|
||||||
onChange={(event) => updateFormField('about', event.currentTarget.value)}
|
initialContent={form.about}
|
||||||
/>
|
onChange={(value) => updateFormField('about', value)}
|
||||||
<label for="about">{t('About myself')}</label>
|
maxLength={500}
|
||||||
</div>
|
/>
|
||||||
|
|
||||||
{/*Нет реализации полей на бэке*/}
|
{/*Нет реализации полей на бэке*/}
|
||||||
{/*<h4>{t('How can I help/skills')}</h4>*/}
|
{/*<h4>{t('How can I help/skills')}</h4>*/}
|
||||||
{/*<div class="pretty-form__item">*/}
|
{/*<div class="pretty-form__item">*/}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user