Feature/progressive image (#322)
* progressive image * progressive image v0.2 * progressive images v0.3 * SimplifiedEditor async load, hydration script moved to the bottom * GrowingTextarea optimization * static images moved to storj --------- Co-authored-by: Igor Lobanov <igor.lobanov@onetwotrip.com>
This commit is contained in:
parent
cbf6daa034
commit
8cad60bdda
Binary file not shown.
Before Width: | Height: | Size: 1.4 MiB |
Binary file not shown.
Before Width: | Height: | Size: 744 KiB |
Binary file not shown.
Before Width: | Height: | Size: 144 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"theme_color": "#111111",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone",
|
||||
"scope": "/",
|
||||
"start_url": "/",
|
||||
"name": "discours.io",
|
||||
"short_name": "discours.io",
|
||||
"description": "Дискурс - коллаборативная журналистика",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/favicon.png",
|
||||
"sizes": "200x200",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -21,7 +21,7 @@ export const AudioHeader = (props: Props) => {
|
|||
return (
|
||||
<div class={clsx(styles.AudioHeader, { [styles.expandedImage]: expandedImage() })}>
|
||||
<div class={styles.cover}>
|
||||
<Image class={styles.image} src={props.cover} alt={props.title} width={200} />
|
||||
<Image class={styles.image} src={props.cover} alt={props.title} width={100} />
|
||||
<Show when={props.cover}>
|
||||
<button type="button" class={styles.expand} onClick={() => setExpandedImage(!expandedImage())}>
|
||||
<Icon name="expand-circle" />
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import { createSignal, For, Show } from 'solid-js'
|
||||
import { createSignal, For, lazy, Show } from 'solid-js'
|
||||
|
||||
import { useLocalize } from '../../../context/localize'
|
||||
import { MediaItem } from '../../../pages/types'
|
||||
import { getDescription } from '../../../utils/meta'
|
||||
import { GrowingTextarea } from '../../_shared/GrowingTextarea'
|
||||
import { Icon } from '../../_shared/Icon'
|
||||
import { Popover } from '../../_shared/Popover'
|
||||
import SimplifiedEditor from '../../Editor/SimplifiedEditor'
|
||||
import { SharePopup, getShareUrl } from '../SharePopup'
|
||||
|
||||
import styles from './AudioPlayer.module.scss'
|
||||
|
||||
const SimplifiedEditor = lazy(() => import('../../Editor/SimplifiedEditor'))
|
||||
const GrowingTextarea = lazy(() => import('../../_shared/GrowingTextarea/GrowingTextarea'))
|
||||
|
||||
type Props = {
|
||||
media: MediaItem[]
|
||||
currentTrackIndex: number
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { clsx } from 'clsx'
|
||||
import { Show, createMemo, createSignal, onMount, For } from 'solid-js'
|
||||
import { Show, createMemo, createSignal, onMount, For, lazy } from 'solid-js'
|
||||
|
||||
import { useLocalize } from '../../context/localize'
|
||||
import { useReactions } from '../../context/reactions'
|
||||
|
@ -8,12 +8,13 @@ import { Author, Reaction, ReactionKind } from '../../graphql/types.gen'
|
|||
import { byCreated } from '../../utils/sortby'
|
||||
import { Button } from '../_shared/Button'
|
||||
import { ShowIfAuthenticated } from '../_shared/ShowIfAuthenticated'
|
||||
import SimplifiedEditor from '../Editor/SimplifiedEditor'
|
||||
|
||||
import { Comment } from './Comment'
|
||||
|
||||
import styles from './Article.module.scss'
|
||||
|
||||
const SimplifiedEditor = lazy(() => import('../Editor/SimplifiedEditor'))
|
||||
|
||||
type CommentsOrder = 'createdAt' | 'rating' | 'newOnly'
|
||||
|
||||
const sortCommentsByRating = (a: Reaction, b: Reaction): -1 | 0 | 1 => {
|
||||
|
|
40
src/components/Article/CoverImage/CoverImage.tsx
Normal file
40
src/components/Article/CoverImage/CoverImage.tsx
Normal file
|
@ -0,0 +1,40 @@
|
|||
import type { CoverImageProps } from './types'
|
||||
|
||||
import { CoverImage1 } from './images/CoverImage1'
|
||||
import { CoverImage10 } from './images/CoverImage10'
|
||||
import { CoverImage11 } from './images/CoverImage11'
|
||||
import { CoverImage12 } from './images/CoverImage12'
|
||||
import { CoverImage2 } from './images/CoverImage2'
|
||||
import { CoverImage3 } from './images/CoverImage3'
|
||||
import { CoverImage4 } from './images/CoverImage4'
|
||||
import { CoverImage5 } from './images/CoverImage5'
|
||||
import { CoverImage6 } from './images/CoverImage6'
|
||||
import { CoverImage7 } from './images/CoverImage7'
|
||||
import { CoverImage8 } from './images/CoverImage8'
|
||||
import { CoverImage9 } from './images/CoverImage9'
|
||||
|
||||
// not pretty, but I don't want to use dynamic imports
|
||||
const coverImages = [
|
||||
CoverImage1,
|
||||
CoverImage2,
|
||||
CoverImage3,
|
||||
CoverImage4,
|
||||
CoverImage5,
|
||||
CoverImage6,
|
||||
CoverImage7,
|
||||
CoverImage8,
|
||||
CoverImage9,
|
||||
CoverImage10,
|
||||
CoverImage11,
|
||||
CoverImage12,
|
||||
]
|
||||
|
||||
let counter = 0
|
||||
export const CoverImage = (props: CoverImageProps) => {
|
||||
const CoverImageComponent = coverImages[counter]
|
||||
counter++
|
||||
if (counter === coverImages.length) {
|
||||
counter = 0
|
||||
}
|
||||
return <CoverImageComponent {...props} />
|
||||
}
|
13
src/components/Article/CoverImage/images/CoverImage1.tsx
Normal file
13
src/components/Article/CoverImage/images/CoverImage1.tsx
Normal file
File diff suppressed because one or more lines are too long
14
src/components/Article/CoverImage/images/CoverImage10.tsx
Normal file
14
src/components/Article/CoverImage/images/CoverImage10.tsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { CoverImageProps } from '../types'
|
||||
|
||||
export const CoverImage10 = (props: CoverImageProps) => (
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 120 120" {...props}>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
stroke="#000"
|
||||
stroke-width=".25"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M-2.531-.107h8.504v8.503zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.905h8.504v8.504zm0 11.907h8.504v8.504zm0 11.904h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.906h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zM9.373-.107h8.504v8.503zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.905h8.504v8.504zm0 11.907h8.504v8.504zm0 11.904h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.906h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zM21.279-.107h8.504v8.503zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.905h8.504v8.504zm0 11.907h8.504v8.504zm0 11.904h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.906h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zM33.184-.107h8.504v8.503zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.905h8.504v8.504zm0 11.907h8.504v8.504zm0 11.904h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.906h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zM45.09-.107h8.504v8.503zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.905h8.504v8.504zm0 11.907h8.504v8.504zm0 11.904h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.906h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zM56.996-.107H65.5v8.503zm0 11.906H65.5v8.504zm0 11.905H65.5v8.504zm0 11.905H65.5v8.504zm0 11.907H65.5v8.504zm0 11.904H65.5v8.504zm0 11.906H65.5v8.504zm0 11.905H65.5v8.504zm0 11.906H65.5v8.504zm0 11.906H65.5v8.504zm0 11.905H65.5v8.504zM68.9-.107h8.504v8.503zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.905h8.504v8.504zm0 11.907h8.504v8.504zm0 11.904h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.906h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zM80.807-.107h8.504v8.503zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.905h8.504v8.504zm0 11.907h8.504v8.504zm0 11.904h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.906h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zM92.713-.107h8.504v8.503zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.905h8.504v8.504zm0 11.907h8.504v8.504zm0 11.904h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.906h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zM104.617-.107h8.504v8.503zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.905h8.504v8.504zm0 11.907h8.504v8.504zm0 11.904h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.906h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zM116.523-.107h8.504v8.503zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.905h8.504v8.504zm0 11.907h8.504v8.504zm0 11.904h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504zm0 11.906h8.504v8.504zm0 11.906h8.504v8.504zm0 11.905h8.504v8.504z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
15
src/components/Article/CoverImage/images/CoverImage11.tsx
Normal file
15
src/components/Article/CoverImage/images/CoverImage11.tsx
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { CoverImageProps } from '../types'
|
||||
|
||||
export const CoverImage11 = (props: CoverImageProps) => (
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 120 120" {...props}>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="4.949"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M2.457-.255v5.262h5.262m9.47-5.262v5.262h5.261m9.469-5.262v5.262h5.262m9.47-5.262v5.262h5.262m9.469-5.262v5.262h5.261m9.47-5.262v5.262h5.262m9.471-5.262v5.262h5.261m9.469-5.262v5.262h5.261M2.457 29.209v5.261h5.262m9.47-5.261v5.261h5.261m9.469-5.261v5.261h5.262m9.47-5.261v5.261h5.262m9.469-5.261v5.261h5.261m9.47-5.261v5.261h5.262m9.471-5.261v5.261h5.261m9.469-5.261v5.261h5.261M2.457 58.671v5.261h5.262m9.47-5.261v5.261h5.261m9.469-5.261v5.261h5.262m9.47-5.261v5.261h5.262m9.469-5.261v5.261h5.261m9.47-5.261v5.261h5.262m9.471-5.261v5.261h5.261m9.469-5.261v5.261h5.261M2.457 88.133v5.261h5.262m9.47-5.261v5.261h5.261m9.469-5.261v5.261h5.262m9.47-5.261v5.261h5.262m9.469-5.261v5.261h5.261m9.47-5.261v5.261h5.262m9.471-5.261v5.261h5.261m9.469-5.261v5.261h5.261M2.457 117.596v2.261m14.732-2.261v2.261m14.73-2.261v2.261m14.732-2.261v2.261m14.731-2.261v2.261m14.731-2.261v2.261m14.733-2.261v2.261m14.73-2.261v2.261M-1.909 19.737H.353m9.47-5.26v5.26h5.262m9.468-5.26v5.26h5.261m9.471-5.26v5.26h5.262m9.471-5.26v5.26h5.261m9.469-5.26v5.26h5.261m9.47-5.26v5.26h5.262m9.469-5.26v5.26h5.261m9.471-5.26v5.26h5.261M-1.909 49.199H.353m9.47-5.26v5.26h5.262m9.468-5.26v5.26h5.261m9.471-5.26v5.26h5.262m9.471-5.26v5.26h5.261m9.469-5.26v5.26h5.261m9.47-5.26v5.26h5.262m9.469-5.26v5.26h5.261m9.471-5.26v5.26h5.261M-1.909 78.663H.353m9.47-5.262v5.262h5.262m9.468-5.262v5.262h5.261m9.471-5.262v5.262h5.262m9.471-5.262v5.262h5.261m9.469-5.262v5.262h5.261m9.47-5.262v5.262h5.262m9.469-5.262v5.262h5.261m9.471-5.262v5.262h5.261M-1.909 108.126H.353m9.47-5.261v5.261h5.262m9.468-5.261v5.261h5.261m9.471-5.261v5.261h5.262m9.471-5.261v5.261h5.261m9.469-5.261v5.261h5.261m9.47-5.261v5.261h5.262m9.469-5.261v5.261h5.261m9.471-5.261v5.261h5.261"
|
||||
/>
|
||||
</svg>
|
||||
)
|
12
src/components/Article/CoverImage/images/CoverImage12.tsx
Normal file
12
src/components/Article/CoverImage/images/CoverImage12.tsx
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { CoverImageProps } from '../types'
|
||||
|
||||
export const CoverImage12 = (props: CoverImageProps) => (
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 120 120" {...props}>
|
||||
<path
|
||||
stroke="#000"
|
||||
stroke-width="3.23"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M-.509-2.401h4.578v4.578H-.509v-4.578zm0 12.819h4.578v4.578H-.509v-4.578zm0 12.817h4.578v4.578H-.509v-4.578zm0 12.82h4.578v4.578H-.509v-4.578zm0 12.819h4.578v4.578H-.509v-4.578zm0 12.818h4.578v4.579H-.509v-4.579zm0 12.82h4.578v4.578H-.509v-4.578zm0 12.818h4.578v4.579H-.509V87.33zm0 12.818h4.578v4.579H-.509v-4.579zm0 12.82h4.578v4.578H-.509v-4.578zM12.311-2.401h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.817h4.578v4.578h-4.578v-4.578zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578V87.33zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578zM25.128-2.401h4.579v4.578h-4.579v-4.578zm0 12.819h4.579v4.578h-4.579v-4.578zm0 12.817h4.579v4.578h-4.579v-4.578zm0 12.82h4.579v4.578h-4.579v-4.578zm0 12.819h4.579v4.578h-4.579v-4.578zm0 12.818h4.579v4.579h-4.579v-4.579zm0 12.82h4.579v4.578h-4.579v-4.578zm0 12.818h4.579v4.579h-4.579V87.33zm0 12.818h4.579v4.579h-4.579v-4.579zm0 12.82h4.579v4.578h-4.579v-4.578zM37.947-2.401h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.817h4.578v4.578h-4.578v-4.578zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578V87.33zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578zM50.767-2.401h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.817h4.578v4.578h-4.578v-4.578zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578V87.33zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578zM63.586-2.401h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.817h4.578v4.578h-4.578v-4.578zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578V87.33zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578zM76.404-2.401h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.817h4.578v4.578h-4.578v-4.578zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578V87.33zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578zM89.223-2.401h4.579v4.578h-4.579v-4.578zm0 12.819h4.579v4.578h-4.579v-4.578zm0 12.817h4.579v4.578h-4.579v-4.578zm0 12.82h4.579v4.578h-4.579v-4.578zm0 12.819h4.579v4.578h-4.579v-4.578zm0 12.818h4.579v4.579h-4.579v-4.579zm0 12.82h4.579v4.578h-4.579v-4.578zm0 12.818h4.579v4.579h-4.579V87.33zm0 12.818h4.579v4.579h-4.579v-4.579zm0 12.82h4.579v4.578h-4.579v-4.578zm12.82-115.369h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.817h4.578v4.578h-4.578v-4.578zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578V87.33zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578zM114.86-2.401h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.817h4.578v4.578h-4.578v-4.578zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.819h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578zm0 12.818h4.578v4.579h-4.578V87.33zm0 12.818h4.578v4.579h-4.578v-4.579zm0 12.82h4.578v4.578h-4.578v-4.578z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
15
src/components/Article/CoverImage/images/CoverImage2.tsx
Normal file
15
src/components/Article/CoverImage/images/CoverImage2.tsx
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { CoverImageProps } from '../types'
|
||||
|
||||
export const CoverImage2 = (props: CoverImageProps) => (
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 120 120" {...props}>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="2"
|
||||
stroke-miterlimit="3.864"
|
||||
d="m-1.753-1.524-3.592 7.179h7.18zm14.36 0-3.59 7.179h7.179zm14.362 0-3.592 7.179h7.18zm14.36 0-3.591 7.179h7.18zm14.361 0-3.591 7.179h7.18zm14.362 0-3.593 7.179h7.181zm14.36 0-3.593 7.179h7.182zm14.359 0-3.59 7.179h7.18zm14.362 0-3.591 7.179h7.18zM-1.753 27.199l-3.592 7.18h7.18zm14.36 0-3.59 7.18h7.179zm14.362 0-3.592 7.18h7.18zm14.36 0-3.591 7.18h7.18zm14.361 0-3.591 7.18h7.18zm14.362 0-3.593 7.18h7.181zm14.36 0-3.593 7.18h7.182zm14.359 0-3.59 7.18h7.18zm14.362 0-3.591 7.18h7.18zM-1.753 55.921l-3.592 7.18h7.18zm14.36 0-3.59 7.18h7.179zm14.362 0-3.592 7.18h7.18zm14.36 0-3.591 7.18h7.18zm14.361 0-3.591 7.18h7.18zm14.362 0-3.593 7.18h7.181zm14.36 0-3.593 7.18h7.182zm14.359 0-3.59 7.18h7.18zm14.362 0-3.591 7.18h7.18zM-1.753 84.64l-3.592 7.182h7.18zm14.36 0-3.59 7.182h7.179zm14.362 0-3.592 7.182h7.18zm14.36 0-3.591 7.182h7.18zm14.361 0-3.591 7.182h7.18zm14.362 0-3.593 7.182h7.181zm14.36 0-3.593 7.182h7.182zm14.359 0-3.59 7.182h7.18zm14.362 0-3.591 7.182h7.18zM-1.753 113.363l-3.592 7.182h7.18zm14.36 0-3.59 7.182h7.179zm14.362 0-3.592 7.182h7.18zm14.36 0-3.591 7.182h7.18zm14.361 0-3.591 7.182h7.18zm14.362 0-3.593 7.182h7.181zm14.36 0-3.593 7.182h7.182zm14.359 0-3.59 7.182h7.18zm14.362 0-3.591 7.182h7.18zM5.428 12.838l-3.593 7.18h7.182zm14.361 0-3.593 7.18h7.181zm14.36 0-3.592 7.18h7.181zm14.36 0-3.591 7.18h7.181zm14.361 0-3.591 7.18h7.18zm14.361 0-3.591 7.18h7.179zm14.361 0-3.591 7.18h7.18zm14.361 0-3.592 7.18h7.181zm14.36 0-3.591 7.18h7.18zM5.428 41.56l-3.593 7.179h7.182zm14.361 0-3.593 7.179h7.181zm14.36 0-3.592 7.179h7.181zm14.36 0-3.591 7.179h7.181zm14.361 0-3.591 7.179h7.18zm14.361 0-3.591 7.179h7.179zm14.361 0-3.591 7.179h7.18zm14.361 0-3.592 7.179h7.181zm14.36 0-3.591 7.179h7.18zM5.428 70.279l-3.593 7.183h7.182zm14.361 0-3.593 7.183h7.181zm14.36 0-3.592 7.183h7.181zm14.36 0-3.591 7.183h7.181zm14.361 0-3.591 7.183h7.18zm14.361 0-3.591 7.183h7.179zm14.361 0-3.591 7.183h7.18zm14.361 0-3.592 7.183h7.181zm14.36 0-3.591 7.183h7.18zM5.428 99.002l-3.593 7.182h7.182zm14.361 0-3.593 7.182h7.181zm14.36 0-3.592 7.182h7.181zm14.36 0-3.591 7.182h7.181zm14.361 0-3.591 7.182h7.18zm14.361 0-3.591 7.182h7.179zm14.361 0-3.591 7.182h7.18zm14.361 0-3.592 7.182h7.181zm14.36 0-3.591 7.182h7.18z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
13
src/components/Article/CoverImage/images/CoverImage3.tsx
Normal file
13
src/components/Article/CoverImage/images/CoverImage3.tsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { CoverImageProps } from '../types'
|
||||
|
||||
export const CoverImage3 = (props: CoverImageProps) => (
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 120 120" {...props}>
|
||||
<path
|
||||
d="M3.647 8.782h5.291M1 .845v5.29m18.521 2.647h5.29M16.874.845v5.29m18.522 2.647h5.289M32.748.845v5.29M51.27 8.782h5.289M48.622.845v5.29m18.52 2.647h5.29M64.495.845v5.29m18.522 2.647h5.29M80.371.845v5.29m18.52 2.647h5.291M96.244.845v5.29m18.521 2.647h5.29M112.118.845v5.29M3.647 24.656h5.291M1 16.719v5.29m18.521 2.647h5.29m-7.937-7.937v5.289m18.522 2.648h5.289m-7.937-7.937v5.289m18.522 2.648h5.289m-7.937-7.937v5.289m18.52 2.648h5.29m-7.937-7.937v5.289m18.522 2.648h5.29m-7.936-7.937v5.289m18.52 2.648h5.291m-7.938-7.937v5.289m18.521 2.648h5.29m-7.937-7.937v5.289M3.647 40.53h5.291M1 32.593v5.29m18.521 2.647h5.29m-7.937-7.938v5.291m18.522 2.647h5.289m-7.937-7.938v5.291M51.27 40.53h5.289m-7.937-7.938v5.291m18.52 2.647h5.29m-7.937-7.938v5.291m18.522 2.647h5.29m-7.936-7.938v5.291m18.52 2.647h5.291m-7.938-7.938v5.291m18.521 2.647h5.29m-7.937-7.938v5.291M3.647 56.403h5.291M1 48.467v5.29m18.521 2.646h5.29m-7.937-7.936v5.29m18.522 2.646h5.289m-7.937-7.936v5.29m18.522 2.646h5.289m-7.937-7.936v5.29m18.52 2.646h5.29m-7.937-7.936v5.29m18.522 2.646h5.29m-7.936-7.936v5.29m18.52 2.646h5.291m-7.938-7.936v5.29m18.521 2.646h5.29m-7.937-7.936v5.29M3.647 72.277h5.291M1 64.34v5.29m18.521 2.647h5.29m-7.937-7.937v5.29m18.522 2.647h5.289m-7.937-7.937v5.29m18.522 2.647h5.289m-7.937-7.937v5.29m18.52 2.647h5.29m-7.937-7.937v5.29m18.522 2.647h5.29m-7.936-7.937v5.29m18.52 2.647h5.291m-7.938-7.937v5.29m18.521 2.647h5.29m-7.937-7.937v5.29M3.647 88.15h5.291M1 80.215v5.289m18.521 2.646h5.29m-7.937-7.935v5.289m18.522 2.646h5.289m-7.937-7.935v5.289M51.27 88.15h5.289m-7.937-7.935v5.289m18.52 2.646h5.29m-7.937-7.935v5.289m18.522 2.646h5.29m-7.936-7.935v5.289m18.52 2.646h5.291m-7.938-7.935v5.289m18.521 2.646h5.29m-7.937-7.935v5.289M3.647 104.025h5.291M1 96.088v5.29m18.521 2.647h5.29m-7.937-7.937v5.29m18.522 2.647h5.289m-7.937-7.937v5.29m18.522 2.647h5.289m-7.937-7.937v5.29m18.52 2.647h5.29m-7.937-7.937v5.29m18.522 2.647h5.29m-7.936-7.937v5.29m18.52 2.647h5.291m-7.938-7.937v5.29m18.521 2.647h5.29m-7.937-7.937v5.29M1 111.963v5.29m15.874-5.29v5.29m15.874-5.29v5.29m15.874-5.29v5.29m15.873-5.29v5.29m15.876-5.29v5.29m15.873-5.29v5.29m15.874-5.29v5.29"
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="3.733"
|
||||
stroke-miterlimit="3.864"
|
||||
/>
|
||||
</svg>
|
||||
)
|
24
src/components/Article/CoverImage/images/CoverImage4.tsx
Normal file
24
src/components/Article/CoverImage/images/CoverImage4.tsx
Normal file
|
@ -0,0 +1,24 @@
|
|||
import { CoverImageProps } from '../types'
|
||||
|
||||
export const CoverImage4 = (props: CoverImageProps) => (
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 120 120" {...props}>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="none"
|
||||
stroke="#231F20"
|
||||
stroke-width=".974"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M-1.149-.979 1.772 120M1.611-.979 4.533 120M4.37-.979 7.293 120M7.133-.979 10.054 120m-.159-92.634 2.92 120.98m2.599-74.662 2.921 100.977M15.414-.979 18.336 120M18.174-.979 21.096 120M20.935-.979 23.856 120m1.299-92.634 2.921 120.98m2.6-58.311 2.922 120.979M29.216-.979 32.137 120M31.978-.979 34.899 120m-4.382-89.798 2.921 120.98M37.499-.979 40.42 120M40.259-.979 43.182 120M43.019-.979 45.94 120m-5.681-89.798 2.922 120.98M48.541-.979 51.462 120M51.301-.979 54.222 120M54.062-.979 56.982 120M49.84 49.547l2.921 120.98M62.343-.979 65.265 120M65.102-.979 68.023 120M67.863-.979 70.785 120M70.624-.979 73.546 120m-2.922-87.462 2.922 120.98M78.904-.979 81.826 120M81.666-.979 84.587 120M84.426-.979 87.348 120M87.188-.979 90.109 120M89.948-.979 92.869 120M92.708-.979 95.63 120m-4.383-32.145 2.922 100.979M98.229-.979 101.15 120M100.989-.979 103.91 120M103.75-.979 106.672 120M106.51-.979 109.432 120M109.271-.979 112.192 120m-5.682-64.286 2.922 120.979M114.791-.979 117.713 120m-.16-120.979L120.474 120M120.312-.979 123.234 120"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="none"
|
||||
stroke="#231F20"
|
||||
stroke-width=".984"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M6.316-.016V120m11.858-60.97v120.016m8.442-165.37v120.015M31.418-.016V120M39.784-.016V120m11.517-31.662v100.014m8.281-132.156v120.016m9.742-113.424v120.016M89.987-.016V120M98.354-.016V120M106.722-.016V120M115.088-.016V120"
|
||||
/>
|
||||
</svg>
|
||||
)
|
15
src/components/Article/CoverImage/images/CoverImage5.tsx
Normal file
15
src/components/Article/CoverImage/images/CoverImage5.tsx
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { CoverImageProps } from '../types'
|
||||
|
||||
export const CoverImage5 = (props: CoverImageProps) => (
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 120 120" {...props}>
|
||||
<path
|
||||
d="M.679 8.708 8.666.722m0 7.986L16.65.722m0 7.986L24.635.722m0 7.986L32.622.722m0 7.986L40.607.722m0 7.986 7.99-7.986m0 7.986L56.58.722m0 7.986L64.568.722m0 7.986L72.555.722m0 7.986L80.542.722m0 7.986L88.527.722m0 7.986L96.513.722m0 7.986L104.5.722m0 7.986 7.985-7.986m0 7.986 7.988-7.986M.679 16.694l7.987-7.986m0 7.986 7.984-7.986m0 7.986 7.985-7.986m0 7.986 7.987-7.986m0 7.986 7.985-7.986m0 7.986 7.99-7.986m0 7.986 7.983-7.986m0 7.986 7.988-7.986m0 7.986 7.987-7.986m0 7.986 7.987-7.986m0 7.986 7.985-7.986m0 7.986 7.986-7.986m0 7.986 7.987-7.986m0 7.986 7.985-7.986m0 7.986 7.988-7.986M.679 24.681l7.987-7.987m0 7.987 7.984-7.987m0 7.987 7.985-7.987m0 7.987 7.987-7.987m0 7.987 7.985-7.987m0 7.987 7.99-7.987m0 7.987 7.983-7.987m0 7.987 7.988-7.987m0 7.987 7.987-7.987m0 7.987 7.987-7.987m0 7.987 7.985-7.987m0 7.987 7.986-7.987m0 7.987 7.987-7.987m0 7.987 7.985-7.987m0 7.987 7.988-7.987M.679 32.666l7.987-7.985m0 7.985 7.984-7.985m0 7.985 7.985-7.985m0 7.985 7.987-7.985m0 7.985 7.985-7.985m0 7.985 7.99-7.985m0 7.985 7.983-7.985m0 7.985 7.988-7.985m0 7.985 7.987-7.985m0 7.985 7.987-7.985m0 7.985 7.985-7.985m0 7.985 7.986-7.985m0 7.985 7.987-7.985m0 7.985 7.985-7.985m0 7.985 7.988-7.985M.679 40.653l7.987-7.987m0 7.987 7.984-7.987m0 7.987 7.985-7.987m0 7.987 7.987-7.987m0 7.987 7.985-7.987m0 7.987 7.99-7.987m0 7.987 7.983-7.987m0 7.987 7.988-7.987m0 7.987 7.987-7.987m0 7.987 7.987-7.987m0 7.987 7.985-7.987m0 7.987 7.986-7.987m0 7.987 7.987-7.987m0 7.987 7.985-7.987m0 7.987 7.988-7.987M.679 48.641l7.987-7.988m0 7.988 7.984-7.988m0 7.988 7.985-7.988m0 7.988 7.987-7.988m0 7.988 7.985-7.988m0 7.988 7.99-7.988m0 7.988 7.983-7.988m0 7.988 7.988-7.988m0 7.988 7.987-7.988m0 7.988 7.987-7.988m0 7.988 7.985-7.988m0 7.988 7.986-7.988m0 7.988 7.987-7.988m0 7.988 7.985-7.988m0 7.988 7.988-7.988M.679 56.625l7.987-7.984m0 7.984 7.984-7.984m0 7.984 7.985-7.984m0 7.984 7.987-7.984m0 7.984 7.985-7.984m0 7.984 7.99-7.984m0 7.984 7.983-7.984m0 7.984 7.988-7.984m0 7.984 7.987-7.984m0 7.984 7.987-7.984m0 7.984 7.985-7.984m0 7.984 7.986-7.984m0 7.984 7.987-7.984m0 7.984 7.985-7.984m0 7.984 7.988-7.984M.679 64.611l7.987-7.986m0 7.986 7.984-7.986m0 7.986 7.985-7.986m0 7.986 7.987-7.986m0 7.986 7.985-7.986m0 7.986 7.99-7.986m0 7.986 7.983-7.986m0 7.986 7.988-7.986m0 7.986 7.987-7.986m0 7.986 7.987-7.986m0 7.986 7.985-7.986m0 7.986 7.986-7.986m0 7.986 7.987-7.986m0 7.986 7.985-7.986m0 7.986 7.988-7.986M.679 72.597l7.987-7.986m0 7.986 7.984-7.986m0 7.986 7.985-7.986m0 7.986 7.987-7.986m0 7.986 7.985-7.986m0 7.986 7.99-7.986m0 7.986 7.983-7.986m0 7.986 7.988-7.986m0 7.986 7.987-7.986m0 7.986 7.987-7.986m0 7.986 7.985-7.986m0 7.986 7.986-7.986m0 7.986 7.987-7.986m0 7.986 7.985-7.986m0 7.986 7.988-7.986M.679 80.585l7.987-7.988m0 7.988 7.984-7.988m0 7.988 7.985-7.988m0 7.988 7.987-7.988m0 7.988 7.985-7.988m0 7.988 7.99-7.988m0 7.988 7.983-7.988m0 7.988 7.988-7.988m0 7.988 7.987-7.988m0 7.988 7.987-7.988m0 7.988 7.985-7.988m0 7.988 7.986-7.988m0 7.988 7.987-7.988m0 7.988 7.985-7.988m0 7.988 7.988-7.988M.679 88.57l7.987-7.985m0 7.985 7.984-7.985m0 7.985 7.985-7.985m0 7.985 7.987-7.985m0 7.985 7.985-7.985m0 7.985 7.99-7.985m0 7.985 7.983-7.985m0 7.985 7.988-7.985m0 7.985 7.987-7.985m0 7.985 7.987-7.985m0 7.985 7.985-7.985m0 7.985 7.986-7.985m0 7.985 7.987-7.985m0 7.985 7.985-7.985m0 7.985 7.988-7.985M.679 96.556l7.987-7.986m0 7.986 7.984-7.986m0 7.986 7.985-7.986m0 7.986 7.987-7.986m0 7.986 7.985-7.986m0 7.986 7.99-7.986m0 7.986 7.983-7.986m0 7.986 7.988-7.986m0 7.986 7.987-7.986m0 7.986 7.987-7.986m0 7.986 7.985-7.986m0 7.986 7.986-7.986m0 7.986 7.987-7.986m0 7.986 7.985-7.986m0 7.986 7.988-7.986M.679 104.543l7.987-7.987m0 7.987 7.984-7.987m0 7.987 7.985-7.987m0 7.987 7.987-7.987m0 7.987 7.985-7.987m0 7.987 7.99-7.987m0 7.987 7.983-7.987m0 7.987 7.988-7.987m0 7.987 7.987-7.987m0 7.987 7.987-7.987m0 7.987 7.985-7.987m0 7.987 7.986-7.987m0 7.987 7.987-7.987m0 7.987 7.985-7.987m0 7.987 7.988-7.987M.679 112.528l7.987-7.985m0 7.985 7.984-7.985m0 7.985 7.985-7.985m0 7.985 7.987-7.985m0 7.985 7.985-7.985m0 7.985 7.99-7.985m0 7.985 7.983-7.985m0 7.985 7.988-7.985m0 7.985 7.987-7.985m0 7.985 7.987-7.985m0 7.985 7.985-7.985m0 7.985 7.986-7.985m0 7.985 7.987-7.985m0 7.985 7.985-7.985m0 7.985 7.988-7.985M.679 120.516l7.987-7.988m0 7.988 7.984-7.988m0 7.988 7.985-7.988m0 7.988 7.987-7.988m0 7.988 7.985-7.988m0 7.988 7.99-7.988m0 7.988 7.983-7.988m0 7.988 7.988-7.988m0 7.988 7.987-7.988m0 7.988 7.987-7.988m0 7.988 7.985-7.988m0 7.988 7.986-7.988m0 7.988 7.987-7.988m0 7.988 7.985-7.988m0 7.988 7.988-7.988"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.878"
|
||||
stroke-miterlimit="3.864"
|
||||
/>
|
||||
</svg>
|
||||
)
|
15
src/components/Article/CoverImage/images/CoverImage6.tsx
Normal file
15
src/components/Article/CoverImage/images/CoverImage6.tsx
Normal file
File diff suppressed because one or more lines are too long
15
src/components/Article/CoverImage/images/CoverImage7.tsx
Normal file
15
src/components/Article/CoverImage/images/CoverImage7.tsx
Normal file
File diff suppressed because one or more lines are too long
209
src/components/Article/CoverImage/images/CoverImage8.tsx
Normal file
209
src/components/Article/CoverImage/images/CoverImage8.tsx
Normal file
|
@ -0,0 +1,209 @@
|
|||
import { CoverImageProps } from '../types'
|
||||
|
||||
export const CoverImage8 = (props: CoverImageProps) => (
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 120 120" {...props}>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M129.44-7.29c0 11.343-11.396 11.343-11.396 22.792m.001 0c0 11.452 11.396 11.452 11.396 22.791 0 11.342-11.396 11.342-11.396 22.796m0 0c0 11.447 11.396 11.447 11.396 22.79 0 11.341-11.396 11.341-11.396 22.788m0 0c0 11.452 11.396 11.452 11.396 22.791M124.886-7.29c0 11.343-11.398 11.343-11.398 22.792"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M113.487 15.502c0 11.452 11.398 11.452 11.398 22.791 0 11.342-11.398 11.342-11.398 22.796m0 0c0 11.447 11.398 11.447 11.398 22.79 0 11.341-11.398 11.341-11.398 22.788m0 0c0 11.452 11.398 11.452 11.398 22.791M120.326-7.29c0 11.343-11.401 11.343-11.401 22.792"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M108.925 15.502c0 11.452 11.401 11.452 11.401 22.791 0 11.342-11.401 11.342-11.401 22.796m0 0c0 11.447 11.401 11.447 11.401 22.79 0 11.341-11.401 11.341-11.401 22.788m0 0c0 11.452 11.401 11.452 11.401 22.791m-4.669-136.83c.018 11.343-11.377 11.361-11.358 22.811"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M104.299 15.438c.018 11.453 11.412 11.435 11.431 22.773.019 11.341-11.377 11.359-11.358 22.814m-.001.001c.019 11.446 11.414 11.428 11.432 22.771.019 11.342-11.377 11.36-11.359 22.807m-.001 0c.019 11.453 11.414 11.435 11.432 22.773M111.096-7.365c.018 11.344-11.375 11.362-11.356 22.811"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M99.739 15.445c.018 11.453 11.41 11.435 11.429 22.773.018 11.341-11.375 11.359-11.356 22.814m0 .001c.019 11.447 11.411 11.428 11.429 22.771.019 11.341-11.374 11.359-11.356 22.806m-.001 0c.019 11.453 11.411 11.435 11.429 22.773m-4.778-136.74c.018 11.343-11.369 11.361-11.351 22.811"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M95.185 15.453c.019 11.452 11.404 11.434 11.423 22.772.018 11.342-11.368 11.36-11.35 22.815m0 .001c.019 11.446 11.405 11.428 11.423 22.771.019 11.341-11.368 11.36-11.351 22.807"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M95.33 106.618c.019 11.453 11.405 11.434 11.423 22.773M101.981-7.351c.018 11.344-11.375 11.363-11.356 22.811m0 0c.018 11.453 11.41 11.435 11.429 22.773.018 11.341-11.375 11.359-11.356 22.814m-.001.001c.019 11.446 11.412 11.428 11.43 22.771.019 11.341-11.375 11.359-11.357 22.806m0 0c.019 11.453 11.412 11.435 11.43 22.773M97.428-7.343C97.445 4 86.044 4.019 86.062 15.468"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M86.062 15.468C86.08 26.92 97.481 26.901 97.5 38.24c.018 11.342-11.383 11.36-11.364 22.814m0 .001c.019 11.447 11.419 11.429 11.437 22.771.02 11.341-11.382 11.359-11.364 22.807m-.001 0c.019 11.452 11.42 11.434 11.438 22.772M92.868-7.336c.018 11.343-11.384 11.362-11.365 22.811"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M81.503 15.475c.018 11.453 11.419 11.435 11.438 22.773.018 11.341-11.384 11.359-11.365 22.814m-.001 0c.019 11.446 11.42 11.428 11.438 22.771.019 11.342-11.383 11.36-11.365 22.807m-.001 0c.019 11.453 11.42 11.435 11.438 22.773M88.308-7.328c.018 11.343-11.377 11.361-11.358 22.81"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M76.949 15.481c.018 11.453 11.412 11.435 11.431 22.773.018 11.341-11.377 11.359-11.358 22.814m-.001.001c.019 11.447 11.414 11.429 11.432 22.771.019 11.341-11.377 11.359-11.359 22.807m0 0c.019 11.452 11.414 11.434 11.432 22.772M83.748-7.321c.018 11.342-11.38 11.361-11.361 22.81"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M72.387 15.489c.018 11.453 11.415 11.434 11.434 22.773.018 11.341-11.38 11.359-11.361 22.814m-.001.001c.02 11.446 11.416 11.428 11.434 22.771.019 11.342-11.378 11.36-11.36 22.807m-.001-.001c.019 11.453 11.415 11.435 11.433 22.773M79.191-7.314c.018 11.343-11.375 11.362-11.356 22.81"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M67.835 15.496c.018 11.453 11.411 11.435 11.43 22.773.018 11.341-11.376 11.359-11.356 22.814m-.001.001c.019 11.446 11.411 11.428 11.429 22.771.019 11.341-11.374 11.359-11.356 22.806m-.001 0c.019 11.453 11.411 11.435 11.429 22.773M74.632-7.307c.017 11.343-11.377 11.362-11.359 22.811"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M63.273 15.504c.018 11.452 11.412 11.434 11.431 22.772.018 11.342-11.377 11.36-11.358 22.815m0 .001c.019 11.446 11.413 11.428 11.431 22.771.019 11.341-11.376 11.359-11.358 22.807m-.001-.001c.019 11.452 11.414 11.434 11.432 22.773M70.078-7.3C70.096 4.044 58.701 4.062 58.72 15.511"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M58.72 15.511c.018 11.453 11.412 11.435 11.431 22.773.018 11.341-11.377 11.359-11.358 22.814m-.001.001c.019 11.446 11.413 11.428 11.431 22.771.019 11.341-11.376 11.359-11.358 22.806m-.001 0c.019 11.453 11.413 11.435 11.431 22.773M65.518-7.292c.018 11.343-11.375 11.361-11.356 22.81"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M54.161 15.518c.018 11.453 11.411 11.435 11.43 22.773.018 11.341-11.376 11.36-11.356 22.814m-.001 0c.019 11.447 11.411 11.429 11.429 22.771.019 11.341-11.374 11.359-11.356 22.807m0 .001c.019 11.452 11.411 11.434 11.429 22.772M60.964-7.285C60.981 4.058 49.581 4.076 49.6 15.525"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M49.6 15.525c.018 11.453 11.418 11.435 11.438 22.773.018 11.341-11.384 11.359-11.365 22.814m-.001.001c.019 11.446 11.42 11.428 11.438 22.771.019 11.342-11.383 11.36-11.365 22.807m-.001-.001c.019 11.453 11.42 11.435 11.438 22.773M56.398-7.278c.018 11.344-11.38 11.362-11.361 22.811"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M45.037 15.532c.018 11.453 11.415 11.435 11.434 22.773.018 11.341-11.38 11.359-11.361 22.814m-.001.001c.019 11.447 11.416 11.428 11.434 22.771.019 11.341-11.379 11.359-11.361 22.806m0 0c.02 11.453 11.416 11.435 11.434 22.773M51.842-7.271C51.859 4.072 40.467 4.091 40.485 15.54"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M40.485 15.54c.018 11.452 11.41 11.434 11.429 22.772.018 11.342-11.375 11.36-11.356 22.815m0 .001c.019 11.446 11.412 11.428 11.43 22.771.019 11.341-11.374 11.36-11.356 22.807m-.001-.001c.019 11.453 11.411 11.434 11.429 22.773M47.284-7.264c.018 11.344-11.38 11.362-11.36 22.811"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M35.924 15.547C35.941 27 47.338 26.981 47.356 38.32c.018 11.341-11.379 11.359-11.36 22.814m0 .001c.019 11.446 11.415 11.428 11.433 22.771.019 11.341-11.378 11.359-11.36 22.806m-.001 0c.019 11.453 11.416 11.435 11.434 22.773M42.722-7.256c.017 11.343-11.377 11.361-11.359 22.811"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M31.363 15.555c.019 11.452 11.412 11.434 11.432 22.772.018 11.342-11.378 11.36-11.359 22.814m0 .001c.018 11.447 11.414 11.428 11.431 22.771.019 11.341-11.377 11.359-11.359 22.807"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M31.508 106.72c.02 11.452 11.414 11.434 11.432 22.772M38.168-7.249C38.186 4.094 26.791 4.113 26.81 15.562m0 0c.019 11.453 11.412 11.435 11.431 22.773.018 11.341-11.377 11.359-11.358 22.814m-.001 0C26.9 72.596 38.296 72.577 38.313 83.92c.019 11.342-11.377 11.36-11.359 22.807m0 0c.019 11.453 11.414 11.435 11.432 22.773M33.614-7.24C33.632 4.102 22.23 4.12 22.25 15.568"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M22.25 15.568c.019 11.453 11.418 11.435 11.437 22.773.018 11.341-11.383 11.359-11.364 22.814m-.001.001c.019 11.447 11.42 11.429 11.438 22.771.019 11.341-11.383 11.359-11.365 22.807m0 0c.019 11.452 11.42 11.434 11.438 22.772M29.055-7.234c.017 11.342-11.386 11.361-11.367 22.81"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M17.688 15.576c.018 11.453 11.421 11.434 11.439 22.774.018 11.34-11.386 11.359-11.367 22.814m0 0c.019 11.446 11.422 11.428 11.439 22.771.019 11.342-11.385 11.36-11.367 22.807"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M17.832 106.741c.019 11.453 11.422 11.435 11.439 22.773M24.492-7.227c.018 11.344-11.377 11.362-11.358 22.81m0 0c.019 11.453 11.413 11.436 11.431 22.773.018 11.341-11.377 11.359-11.358 22.814m-.001.001c.019 11.446 11.413 11.428 11.431 22.771.02 11.341-11.376 11.359-11.358 22.806m-.001 0c.019 11.453 11.414 11.435 11.432 22.773M20.043-7.29c0 11.343-11.396 11.343-11.396 22.792"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M8.646 15.502c0 11.452 11.396 11.452 11.396 22.791 0 11.342-11.396 11.342-11.396 22.796m0 0c0 11.447 11.396 11.447 11.396 22.79 0 11.341-11.396 11.341-11.396 22.788m0 0c0 11.452 11.396 11.452 11.396 22.791M15.487-7.29c0 11.343-11.396 11.343-11.396 22.792"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M4.092 15.502c0 11.452 11.396 11.452 11.396 22.791 0 11.342-11.396 11.342-11.396 22.796m0 0c0 11.447 11.396 11.447 11.396 22.79 0 11.341-11.396 11.341-11.396 22.788m0 0c0 11.452 11.396 11.452 11.396 22.791M10.927-7.29C10.927 4.053-.47 4.053-.47 15.502"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M-.47 15.502c0 11.452 11.396 11.452 11.396 22.791C10.926 49.635-.47 49.635-.47 61.089m0 0c0 11.447 11.396 11.447 11.396 22.79C10.926 95.22-.47 95.22-.47 106.667m0 0c0 11.452 11.396 11.452 11.396 22.791M6.371-7.29c0 11.343-11.393 11.343-11.393 22.792"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M-5.021 15.502c0 11.452 11.393 11.452 11.393 22.791 0 11.342-11.393 11.342-11.393 22.796m0 0c0 11.447 11.393 11.447 11.393 22.79 0 11.341-11.393 11.341-11.393 22.788m0 0c0 11.452 11.393 11.452 11.393 22.791"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="1.608"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M-9.59 15.502c0 11.452 11.403 11.452 11.403 22.791 0 11.342-11.403 11.342-11.403 22.796m0 0c0 11.447 11.403 11.447 11.403 22.79C1.813 95.22-9.59 95.22-9.59 106.667m0 0c0 11.452 11.403 11.452 11.403 22.791"
|
||||
/>
|
||||
</svg>
|
||||
)
|
13
src/components/Article/CoverImage/images/CoverImage9.tsx
Normal file
13
src/components/Article/CoverImage/images/CoverImage9.tsx
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { CoverImageProps } from '../types'
|
||||
|
||||
export const CoverImage9 = (props: CoverImageProps) => (
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 120 120" {...props}>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width="5"
|
||||
stroke-miterlimit="3.864"
|
||||
d="M-23.957 4.94c21.724 0 21.724-3.6 43.237-3.6 21.512 0 21.512 3.601 43.234 3.601m.001-.001c21.724 0 21.724-3.601 43.237-3.601 21.515 0 21.515 3.601 43.237 3.601m-172.946 8.649c21.724 0 21.724-3.603 43.237-3.603 21.512 0 21.512 3.603 43.234 3.603m.001 0c21.724 0 21.724-3.603 43.237-3.603 21.515 0 21.515 3.603 43.237 3.603m-172.946 8.646c21.724 0 21.724-3.603 43.237-3.603 21.512 0 21.512 3.603 43.234 3.603m.001 0c21.724 0 21.724-3.603 43.237-3.603 21.515 0 21.515 3.603 43.237 3.603m-172.946 8.647c21.724 0 21.724-3.6 43.237-3.6 21.512 0 21.512 3.6 43.234 3.6m.001 0c21.724 0 21.724-3.6 43.237-3.6 21.515 0 21.515 3.6 43.237 3.6m-172.946 8.649c21.724 0 21.724-3.604 43.237-3.604 21.512 0 21.512 3.604 43.234 3.604m.001 0c21.724 0 21.724-3.604 43.237-3.604 21.515 0 21.515 3.604 43.237 3.604m-172.946 8.647c21.724 0 21.724-3.604 43.237-3.604 21.512 0 21.512 3.604 43.234 3.604m.001 0c21.724 0 21.724-3.604 43.237-3.604 21.515 0 21.515 3.604 43.237 3.604m-172.946 8.645c21.724 0 21.724-3.6 43.237-3.6 21.512 0 21.512 3.6 43.234 3.6m.001 0c21.724 0 21.724-3.6 43.237-3.6 21.515 0 21.515 3.6 43.237 3.6m-172.946 8.65c21.724 0 21.724-3.603 43.237-3.603 21.512 0 21.512 3.603 43.234 3.603m.001 0c21.724 0 21.724-3.603 43.237-3.603 21.515 0 21.515 3.603 43.237 3.603m-172.946 8.646c21.724 0 21.724-3.603 43.237-3.603 21.512 0 21.512 3.603 43.234 3.603m.001 0c21.724 0 21.724-3.603 43.237-3.603 21.515 0 21.515 3.603 43.237 3.603m-172.946 8.647c21.724 0 21.724-3.604 43.237-3.604 21.512 0 21.512 3.604 43.234 3.604m.001 0c21.724 0 21.724-3.604 43.237-3.604 21.515 0 21.515 3.604 43.237 3.604m-172.946 8.646c21.724 0 21.724-3.604 43.237-3.604 21.512 0 21.512 3.604 43.234 3.604m.001 0c21.724 0 21.724-3.604 43.237-3.604 21.515 0 21.515 3.604 43.237 3.604m-172.946 8.649c21.724 0 21.724-3.604 43.237-3.604 21.512 0 21.512 3.604 43.234 3.604m.001 0c21.724 0 21.724-3.604 43.237-3.604 21.515 0 21.515 3.604 43.237 3.604m-172.946 8.646c21.724 0 21.724-3.603 43.237-3.603 21.512 0 21.512 3.603 43.234 3.603m.001 0c21.724 0 21.724-3.603 43.237-3.603 21.515 0 21.515 3.603 43.237 3.603m-172.946 8.647c21.724 0 21.724-3.604 43.237-3.604 21.512 0 21.512 3.604 43.234 3.604m.001 0c21.724 0 21.724-3.604 43.237-3.604 21.515 0 21.515 3.604 43.237 3.604"
|
||||
/>
|
||||
</svg>
|
||||
)
|
1
src/components/Article/CoverImage/index.ts
Normal file
1
src/components/Article/CoverImage/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { CoverImage } from './CoverImage'
|
3
src/components/Article/CoverImage/types.ts
Normal file
3
src/components/Article/CoverImage/types.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
export type CoverImageProps = {
|
||||
class?: string
|
||||
}
|
|
@ -2,8 +2,10 @@ import type { Author, Shout } from '../../graphql/types.gen'
|
|||
|
||||
import { getPagePath } from '@nanostores/router'
|
||||
import { createPopper } from '@popperjs/core'
|
||||
import { Link } from '@solidjs/meta'
|
||||
import { clsx } from 'clsx'
|
||||
import { createEffect, For, createMemo, onMount, Show, createSignal, onCleanup } from 'solid-js'
|
||||
import { isServer } from 'solid-js/web'
|
||||
|
||||
import { useLocalize } from '../../context/localize'
|
||||
import { useReactions } from '../../context/reactions'
|
||||
|
@ -52,6 +54,8 @@ const scrollTo = (el: HTMLElement) => {
|
|||
})
|
||||
}
|
||||
|
||||
const imgSrcRegExp = /<img[^>]+src\s*=\s*["']([^"']+)["']/gi
|
||||
|
||||
export const FullArticle = (props: Props) => {
|
||||
const [selectedImage, setSelectedImage] = createSignal('')
|
||||
|
||||
|
@ -95,6 +99,26 @@ export const FullArticle = (props: Props) => {
|
|||
return props.article.body
|
||||
})
|
||||
|
||||
const imageUrls = createMemo(() => {
|
||||
if (!body()) {
|
||||
return []
|
||||
}
|
||||
|
||||
if (isServer) {
|
||||
const result: string[] = []
|
||||
let match: RegExpMatchArray
|
||||
|
||||
while ((match = imgSrcRegExp.exec(body())) !== null) {
|
||||
result.push(match[1])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const imageElements = document.querySelectorAll<HTMLImageElement>('#shoutBody img')
|
||||
// eslint-disable-next-line unicorn/prefer-spread
|
||||
return Array.from(imageElements).map((img) => img.src)
|
||||
})
|
||||
|
||||
const media = createMemo<MediaItem[]>(() => {
|
||||
try {
|
||||
return JSON.parse(props.article.media)
|
||||
|
@ -261,6 +285,7 @@ export const FullArticle = (props: Props) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<For each={imageUrls()}>{(imageUrl) => <Link rel="preload" as="image" href={imageUrl} />}</For>
|
||||
<div class="wide-container">
|
||||
<div class="row position-relative">
|
||||
<article
|
||||
|
@ -296,7 +321,7 @@ export const FullArticle = (props: Props) => {
|
|||
props.article.layout !== 'image'
|
||||
}
|
||||
>
|
||||
<Image width={1600} alt={props.article.title} src={props.article.cover} />
|
||||
<Image width={800} alt={props.article.title} src={props.article.cover} />
|
||||
</Show>
|
||||
</div>
|
||||
</Show>
|
||||
|
|
|
@ -2,6 +2,7 @@ import { clsx } from 'clsx'
|
|||
|
||||
import { useLocalize } from '../../context/localize'
|
||||
import { showModal } from '../../stores/ui'
|
||||
import { Image } from '../_shared/Image'
|
||||
|
||||
import styles from './Banner.module.scss'
|
||||
|
||||
|
@ -22,7 +23,11 @@ export default () => {
|
|||
</p>
|
||||
</div>
|
||||
<div class={clsx(styles.discoursBannerImage, 'col-lg-12 offset-lg-2')}>
|
||||
<img src="/discours-banner.jpg" alt={t('Discours')} />
|
||||
<Image
|
||||
src="https://images.discours.io/unsafe/production/image/discours-banner.jpg"
|
||||
alt={t('Discours')}
|
||||
width={600}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -27,6 +27,7 @@ import { hideModal, showModal } from '../../stores/ui'
|
|||
import { Button } from '../_shared/Button'
|
||||
import { Icon } from '../_shared/Icon'
|
||||
import { Popover } from '../_shared/Popover'
|
||||
import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient'
|
||||
import { Modal } from '../Nav/Modal'
|
||||
|
||||
import { Figcaption } from './extensions/Figcaption'
|
||||
|
@ -59,13 +60,16 @@ type Props = {
|
|||
isCancelButtonVisible?: boolean
|
||||
}
|
||||
|
||||
export const MAX_DESCRIPTION_LIMIT = 400
|
||||
const DEFAULT_MAX_LENGTH = 400
|
||||
|
||||
const SimplifiedEditor = (props: Props) => {
|
||||
const { t } = useLocalize()
|
||||
const [counter, setCounter] = createSignal<number>()
|
||||
const [shouldShowLinkBubbleMenu, setShouldShowLinkBubbleMenu] = createSignal(false)
|
||||
const isCancelButtonVisible = createMemo(() => props.isCancelButtonVisible !== false)
|
||||
|
||||
const maxLength = props.maxLength ?? DEFAULT_MAX_LENGTH
|
||||
|
||||
const wrapperEditorElRef: {
|
||||
current: HTMLElement
|
||||
} = {
|
||||
|
@ -116,9 +120,8 @@ const SimplifiedEditor = (props: Props) => {
|
|||
Link.configure({
|
||||
openOnClick: false,
|
||||
}),
|
||||
|
||||
CharacterCount.configure({
|
||||
limit: MAX_DESCRIPTION_LIMIT,
|
||||
limit: maxLength,
|
||||
}),
|
||||
Blockquote.configure({
|
||||
HTMLAttributes: {
|
||||
|
@ -262,132 +265,134 @@ const SimplifiedEditor = (props: Props) => {
|
|||
setShouldShowLinkBubbleMenu(true)
|
||||
}
|
||||
return (
|
||||
<div
|
||||
ref={(el) => (wrapperEditorElRef.current = el)}
|
||||
class={clsx(styles.SimplifiedEditor, {
|
||||
[styles.smallHeight]: props.smallHeight,
|
||||
[styles.minimal]: props.variant === 'minimal',
|
||||
[styles.bordered]: props.variant === 'bordered',
|
||||
[styles.isFocused]: isFocused() || !isEmpty(),
|
||||
[styles.labelVisible]: props.label && counter() > 0,
|
||||
})}
|
||||
>
|
||||
<Show when={props.maxLength && editor()}>
|
||||
<div class={styles.limit}>{MAX_DESCRIPTION_LIMIT - counter()}</div>
|
||||
</Show>
|
||||
<Show when={props.label && counter() > 0}>
|
||||
<div class={styles.label}>{props.label}</div>
|
||||
</Show>
|
||||
<div style={props.maxHeight && maxHeightStyle} ref={(el) => (editorElRef.current = el)} />
|
||||
<Show when={!props.onlyBubbleControls}>
|
||||
<div class={clsx(styles.controls, { [styles.alwaysVisible]: props.controlsAlwaysVisible })}>
|
||||
<div class={styles.actions}>
|
||||
<Popover content={t('Bold')}>
|
||||
{(triggerRef: (el) => void) => (
|
||||
<button
|
||||
ref={triggerRef}
|
||||
type="button"
|
||||
class={clsx(styles.actionButton, { [styles.active]: isBold() })}
|
||||
onClick={() => editor().chain().focus().toggleBold().run()}
|
||||
>
|
||||
<Icon name="editor-bold" />
|
||||
</button>
|
||||
)}
|
||||
</Popover>
|
||||
<Popover content={t('Italic')}>
|
||||
{(triggerRef: (el) => void) => (
|
||||
<button
|
||||
ref={triggerRef}
|
||||
type="button"
|
||||
class={clsx(styles.actionButton, { [styles.active]: isItalic() })}
|
||||
onClick={() => editor().chain().focus().toggleItalic().run()}
|
||||
>
|
||||
<Icon name="editor-italic" />
|
||||
</button>
|
||||
)}
|
||||
</Popover>
|
||||
<Popover content={t('Add url')}>
|
||||
{(triggerRef: (el) => void) => (
|
||||
<button
|
||||
ref={triggerRef}
|
||||
type="button"
|
||||
onClick={handleShowLinkBubble}
|
||||
class={clsx(styles.actionButton, { [styles.active]: isLink() })}
|
||||
>
|
||||
<Icon name="editor-link" />
|
||||
</button>
|
||||
)}
|
||||
</Popover>
|
||||
<Show when={props.quoteEnabled}>
|
||||
<Popover content={t('Add blockquote')}>
|
||||
<ShowOnlyOnClient>
|
||||
<div
|
||||
ref={(el) => (wrapperEditorElRef.current = el)}
|
||||
class={clsx(styles.SimplifiedEditor, {
|
||||
[styles.smallHeight]: props.smallHeight,
|
||||
[styles.minimal]: props.variant === 'minimal',
|
||||
[styles.bordered]: props.variant === 'bordered',
|
||||
[styles.isFocused]: isFocused() || !isEmpty(),
|
||||
[styles.labelVisible]: props.label && counter() > 0,
|
||||
})}
|
||||
>
|
||||
<Show when={props.maxLength && editor()}>
|
||||
<div class={styles.limit}>{maxLength - counter()}</div>
|
||||
</Show>
|
||||
<Show when={props.label && counter() > 0}>
|
||||
<div class={styles.label}>{props.label}</div>
|
||||
</Show>
|
||||
<div style={props.maxHeight && maxHeightStyle} ref={(el) => (editorElRef.current = el)} />
|
||||
<Show when={!props.onlyBubbleControls}>
|
||||
<div class={clsx(styles.controls, { [styles.alwaysVisible]: props.controlsAlwaysVisible })}>
|
||||
<div class={styles.actions}>
|
||||
<Popover content={t('Bold')}>
|
||||
{(triggerRef: (el) => void) => (
|
||||
<button
|
||||
ref={triggerRef}
|
||||
type="button"
|
||||
onClick={() => editor().chain().focus().toggleBlockquote().run()}
|
||||
class={clsx(styles.actionButton, { [styles.active]: isBlockquote() })}
|
||||
class={clsx(styles.actionButton, { [styles.active]: isBold() })}
|
||||
onClick={() => editor().chain().focus().toggleBold().run()}
|
||||
>
|
||||
<Icon name="editor-quote" />
|
||||
<Icon name="editor-bold" />
|
||||
</button>
|
||||
)}
|
||||
</Popover>
|
||||
</Show>
|
||||
<Show when={props.imageEnabled}>
|
||||
<Popover content={t('Add image')}>
|
||||
{(triggerRef: (el) => void) => (
|
||||
<Popover content={t('Italic')}>
|
||||
{(triggerRef) => (
|
||||
<button
|
||||
ref={triggerRef}
|
||||
type="button"
|
||||
onClick={() => showModal('simplifiedEditorUploadImage')}
|
||||
class={clsx(styles.actionButton, { [styles.active]: isBlockquote() })}
|
||||
class={clsx(styles.actionButton, { [styles.active]: isItalic() })}
|
||||
onClick={() => editor().chain().focus().toggleItalic().run()}
|
||||
>
|
||||
<Icon name="editor-image-dd-full" />
|
||||
<Icon name="editor-italic" />
|
||||
</button>
|
||||
)}
|
||||
</Popover>
|
||||
<Popover content={t('Add url')}>
|
||||
{(triggerRef) => (
|
||||
<button
|
||||
ref={triggerRef}
|
||||
type="button"
|
||||
onClick={handleShowLinkBubble}
|
||||
class={clsx(styles.actionButton, { [styles.active]: isLink() })}
|
||||
>
|
||||
<Icon name="editor-link" />
|
||||
</button>
|
||||
)}
|
||||
</Popover>
|
||||
<Show when={props.quoteEnabled}>
|
||||
<Popover content={t('Add blockquote')}>
|
||||
{(triggerRef) => (
|
||||
<button
|
||||
ref={triggerRef}
|
||||
type="button"
|
||||
onClick={() => editor().chain().focus().toggleBlockquote().run()}
|
||||
class={clsx(styles.actionButton, { [styles.active]: isBlockquote() })}
|
||||
>
|
||||
<Icon name="editor-quote" />
|
||||
</button>
|
||||
)}
|
||||
</Popover>
|
||||
</Show>
|
||||
<Show when={props.imageEnabled}>
|
||||
<Popover content={t('Add image')}>
|
||||
{(triggerRef) => (
|
||||
<button
|
||||
ref={triggerRef}
|
||||
type="button"
|
||||
onClick={() => showModal('simplifiedEditorUploadImage')}
|
||||
class={clsx(styles.actionButton, { [styles.active]: isBlockquote() })}
|
||||
>
|
||||
<Icon name="editor-image-dd-full" />
|
||||
</button>
|
||||
)}
|
||||
</Popover>
|
||||
</Show>
|
||||
</div>
|
||||
<Show when={!props.onChange}>
|
||||
<div class={styles.buttons}>
|
||||
<Show when={isCancelButtonVisible()}>
|
||||
<Button value={t('Cancel')} variant="secondary" onClick={handleClear} />
|
||||
</Show>
|
||||
<Button
|
||||
value={props.submitButtonText ?? t('Send')}
|
||||
variant="primary"
|
||||
disabled={isEmpty()}
|
||||
onClick={() => props.onSubmit(html())}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
<Show when={!props.onChange}>
|
||||
<div class={styles.buttons}>
|
||||
<Show when={isCancelButtonVisible()}>
|
||||
<Button value={t('Cancel')} variant="secondary" onClick={handleClear} />
|
||||
</Show>
|
||||
<Button
|
||||
value={props.submitButtonText ?? t('Send')}
|
||||
variant="primary"
|
||||
disabled={isEmpty()}
|
||||
onClick={() => props.onSubmit(html())}
|
||||
</Show>
|
||||
<Show when={props.imageEnabled}>
|
||||
<Portal>
|
||||
<Modal variant="narrow" name="simplifiedEditorUploadImage">
|
||||
<UploadModalContent
|
||||
onClose={(value) => {
|
||||
renderImage(value)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={props.imageEnabled}>
|
||||
<Portal>
|
||||
<Modal variant="narrow" name="simplifiedEditorUploadImage">
|
||||
<UploadModalContent
|
||||
onClose={(value) => {
|
||||
renderImage(value)
|
||||
}}
|
||||
/>
|
||||
</Modal>
|
||||
</Portal>
|
||||
</Show>
|
||||
<Show when={props.onlyBubbleControls}>
|
||||
<TextBubbleMenu
|
||||
shouldShow={true}
|
||||
isCommonMarkup={true}
|
||||
</Modal>
|
||||
</Portal>
|
||||
</Show>
|
||||
<Show when={props.onlyBubbleControls}>
|
||||
<TextBubbleMenu
|
||||
shouldShow={true}
|
||||
isCommonMarkup={true}
|
||||
editor={editor()}
|
||||
ref={(el) => (textBubbleMenuRef.current = el)}
|
||||
/>
|
||||
</Show>
|
||||
<LinkBubbleMenuModule
|
||||
shouldShow={shouldShowLinkBubbleMenu()}
|
||||
editor={editor()}
|
||||
ref={(el) => (textBubbleMenuRef.current = el)}
|
||||
ref={(el) => (linkBubbleMenuRef.current = el)}
|
||||
onClose={() => setShouldShowLinkBubbleMenu(false)}
|
||||
/>
|
||||
</Show>
|
||||
<LinkBubbleMenuModule
|
||||
shouldShow={shouldShowLinkBubbleMenu()}
|
||||
editor={editor()}
|
||||
ref={(el) => (linkBubbleMenuRef.current = el)}
|
||||
onClose={() => setShouldShowLinkBubbleMenu(false)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ShowOnlyOnClient>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
import type { Editor } from '@tiptap/core'
|
||||
|
||||
import { clsx } from 'clsx'
|
||||
import { Switch, Match, createSignal, Show, onMount, onCleanup, createEffect } from 'solid-js'
|
||||
import { Switch, Match, createSignal, Show, onMount, onCleanup, createEffect, lazy } from 'solid-js'
|
||||
import { createEditorTransaction } from 'solid-tiptap'
|
||||
|
||||
import { useLocalize } from '../../../context/localize'
|
||||
import { Icon } from '../../_shared/Icon'
|
||||
import { Popover } from '../../_shared/Popover'
|
||||
import { InsertLinkForm } from '../InsertLinkForm'
|
||||
import SimplifiedEditor from '../SimplifiedEditor'
|
||||
|
||||
import styles from './TextBubbleMenu.module.scss'
|
||||
|
||||
const SimplifiedEditor = lazy(() => import('../../Editor/SimplifiedEditor'))
|
||||
|
||||
type BubbleMenuProps = {
|
||||
editor: Editor
|
||||
isCommonMarkup: boolean
|
||||
|
|
|
@ -94,7 +94,6 @@
|
|||
}
|
||||
|
||||
.shoutCardCover {
|
||||
background: rgb(0 0 0 / 30%);
|
||||
height: 0;
|
||||
margin-bottom: 1.6rem;
|
||||
overflow: hidden;
|
||||
|
@ -103,6 +102,10 @@
|
|||
transform-origin: 50% 50%;
|
||||
transition: transform 1s ease-in-out;
|
||||
|
||||
&.loading {
|
||||
background: rgb(0 0 0 / 20%);
|
||||
}
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
|
@ -825,3 +828,7 @@
|
|||
.shoutTopicTop {
|
||||
margin-bottom: 0.4rem !important;
|
||||
}
|
||||
|
||||
.placeholderCoverImage {
|
||||
position: absolute;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import { getDescription } from '../../../utils/meta'
|
|||
import { Icon } from '../../_shared/Icon'
|
||||
import { Image } from '../../_shared/Image'
|
||||
import { Popover } from '../../_shared/Popover'
|
||||
import { CoverImage } from '../../Article/CoverImage'
|
||||
import { getShareUrl, SharePopup } from '../../Article/SharePopup'
|
||||
import { ShoutRatingControl } from '../../Article/ShoutRatingControl'
|
||||
import { AuthorLink } from '../../Author/AhtorLink'
|
||||
|
@ -21,7 +22,8 @@ import { FeedArticlePopup } from '../FeedArticlePopup'
|
|||
import styles from './ArticleCard.module.scss'
|
||||
import stylesHeader from '../../Nav/Header/Header.module.scss'
|
||||
|
||||
interface ArticleCardProps {
|
||||
export type ArticleCardProps = {
|
||||
// TODO: refactor this, please
|
||||
settings?: {
|
||||
noicon?: boolean
|
||||
noimage?: boolean
|
||||
|
@ -44,9 +46,17 @@ interface ArticleCardProps {
|
|||
withViewed?: boolean
|
||||
noAuthorLink?: boolean
|
||||
}
|
||||
desktopCoverSize: 'XS' | 'S' | 'M' | 'L'
|
||||
article: Shout
|
||||
}
|
||||
|
||||
const desktopCoverImageWidths: Record<ArticleCardProps['desktopCoverSize'], number> = {
|
||||
XS: 300,
|
||||
S: 400,
|
||||
M: 600,
|
||||
L: 800,
|
||||
}
|
||||
|
||||
const getTitleAndSubtitle = (
|
||||
article: Shout,
|
||||
): {
|
||||
|
@ -98,11 +108,12 @@ export const ArticleCard = (props: ArticleCardProps) => {
|
|||
}
|
||||
|
||||
const [isActionPopupActive, setIsActionPopupActive] = createSignal(false)
|
||||
const [isCoverImageLoadError, setIsCoverImageLoadError] = createSignal(false)
|
||||
const [isCoverImageLoading, setIsCoverImageLoading] = createSignal(true)
|
||||
|
||||
return (
|
||||
<section
|
||||
class={clsx(styles.shoutCard, `${props.settings?.additionalClass || ''}`)}
|
||||
classList={{
|
||||
class={clsx(styles.shoutCard, props.settings?.additionalClass, {
|
||||
[styles.shoutCardShort]: props.settings?.isShort,
|
||||
[styles.shoutCardPhotoBottom]: props.settings?.noimage && props.settings?.photoBottom,
|
||||
[styles.shoutCardFeed]: props.settings?.isFeedMode,
|
||||
|
@ -115,13 +126,29 @@ export const ArticleCard = (props: ArticleCardProps) => {
|
|||
[styles.shoutCardSingle]: props.settings?.isSingle,
|
||||
[styles.shoutCardBeside]: props.settings?.isBeside,
|
||||
[styles.shoutCardNoImage]: !props.article.cover,
|
||||
}}
|
||||
})}
|
||||
>
|
||||
<Show when={!props.settings?.noimage && !props.settings?.isFeedMode}>
|
||||
<div class={styles.shoutCardCoverContainer}>
|
||||
<div class={styles.shoutCardCover}>
|
||||
<Show when={props.article.cover}>
|
||||
<Image src={props.article.cover} alt={title} width={1200} />
|
||||
<div
|
||||
class={clsx(styles.shoutCardCover, {
|
||||
[styles.loading]: props.article.cover && isCoverImageLoading(),
|
||||
})}
|
||||
>
|
||||
<Show
|
||||
when={props.article.cover && !isCoverImageLoadError()}
|
||||
fallback={<CoverImage class={styles.placeholderCoverImage} />}
|
||||
>
|
||||
<Image
|
||||
src={props.article.cover}
|
||||
alt={title}
|
||||
width={desktopCoverImageWidths[props.desktopCoverSize]}
|
||||
onError={() => {
|
||||
setIsCoverImageLoadError(true)
|
||||
setIsCoverImageLoading(false)
|
||||
}}
|
||||
onLoad={() => setIsCoverImageLoading(false)}
|
||||
/>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -214,7 +241,7 @@ export const ArticleCard = (props: ArticleCardProps) => {
|
|||
</div>
|
||||
</Show>
|
||||
<div class={styles.shoutCardCover}>
|
||||
<Image src={props.article.cover} alt={title} width={1200} loading="lazy" />
|
||||
<Image src={props.article.cover} alt={title} width={600} loading="lazy" />
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
|
|
|
@ -85,12 +85,14 @@ export const Beside = (props: Props) => {
|
|||
<ArticleCard
|
||||
article={value as Shout}
|
||||
settings={{ noimage: true, nodate: props.nodate }}
|
||||
desktopCoverSize="XS"
|
||||
/>
|
||||
</Show>
|
||||
<Show when={props.wrapper === 'top-article' && value?.slug}>
|
||||
<ArticleCard
|
||||
article={value as Shout}
|
||||
settings={{ noimage: true, noauthor: true, nodate: true, isShort: true }}
|
||||
desktopCoverSize="XS"
|
||||
/>
|
||||
</Show>
|
||||
</li>
|
||||
|
@ -103,6 +105,7 @@ export const Beside = (props: Props) => {
|
|||
<ArticleCard
|
||||
article={props.beside}
|
||||
settings={{ isBigTitle: true, isBeside: true, nodate: props.nodate }}
|
||||
desktopCoverSize="L"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -30,6 +30,7 @@ export default (props: GroupProps) => {
|
|||
isBigTitle: true,
|
||||
nodate: true,
|
||||
}}
|
||||
desktopCoverSize="M"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -43,6 +44,7 @@ export default (props: GroupProps) => {
|
|||
<ArticleCard
|
||||
article={a}
|
||||
settings={{ nosubtitle: false, noicon: true, isBigTitle: true, nodate: true }}
|
||||
desktopCoverSize="XS"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -63,6 +65,7 @@ export default (props: GroupProps) => {
|
|||
isFloorImportant: true,
|
||||
nodate: true,
|
||||
}}
|
||||
desktopCoverSize="XS"
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
|
@ -80,6 +83,7 @@ export default (props: GroupProps) => {
|
|||
isFloorImportant: true,
|
||||
nodate: true,
|
||||
}}
|
||||
desktopCoverSize="XS"
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
|
|
|
@ -23,6 +23,7 @@ export const Row1 = (props: {
|
|||
noAuthorLink: props.noAuthorLink,
|
||||
noauthor: props.noauthor,
|
||||
}}
|
||||
desktopCoverSize="L"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,6 +3,7 @@ import type { Shout } from '../../graphql/types.gen'
|
|||
import { createComputed, createSignal, Show, For } from 'solid-js'
|
||||
|
||||
import { ArticleCard } from './ArticleCard'
|
||||
import { ArticleCardProps } from './ArticleCard/ArticleCard'
|
||||
|
||||
const x = [
|
||||
['12', '12'],
|
||||
|
@ -19,6 +20,7 @@ export const Row2 = (props: {
|
|||
}) => {
|
||||
const [y, setY] = createSignal(0)
|
||||
|
||||
// FIXME: random can break hydration
|
||||
createComputed(() => setY(Math.floor(Math.random() * x.length)))
|
||||
|
||||
return (
|
||||
|
@ -28,20 +30,37 @@ export const Row2 = (props: {
|
|||
<div class="row">
|
||||
<For each={props.articles}>
|
||||
{(a, i) => {
|
||||
// FIXME: refactor this, too ugly now
|
||||
const className = `col-md-${props.isEqual ? '12' : x[y()][i()]}`
|
||||
let desktopCoverSize: ArticleCardProps['desktopCoverSize']
|
||||
|
||||
switch (className) {
|
||||
case 'col-md-8': {
|
||||
desktopCoverSize = 'S'
|
||||
break
|
||||
}
|
||||
case 'col-md-12': {
|
||||
desktopCoverSize = 'M'
|
||||
break
|
||||
}
|
||||
default: {
|
||||
desktopCoverSize = 'L'
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Show when={!!a}>
|
||||
<div class={`col-md-${props.isEqual ? '12' : x[y()][i()]}`}>
|
||||
<ArticleCard
|
||||
article={a}
|
||||
settings={{
|
||||
isWithCover: props.isEqual || x[y()][i()] === '16',
|
||||
nodate: props.isEqual || props.nodate,
|
||||
noAuthorLink: props.noAuthorLink,
|
||||
noauthor: props.noauthor,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
<div class={className}>
|
||||
<ArticleCard
|
||||
article={a}
|
||||
settings={{
|
||||
isWithCover: props.isEqual || x[y()][i()] === '16',
|
||||
nodate: props.isEqual || props.nodate,
|
||||
noAuthorLink: props.noAuthorLink,
|
||||
noauthor: props.noauthor,
|
||||
}}
|
||||
desktopCoverSize={desktopCoverSize}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
</For>
|
||||
|
|
|
@ -28,6 +28,7 @@ export const Row3 = (props: {
|
|||
noAuthorLink: props.noAuthorLink,
|
||||
noauthor: props.noauthor,
|
||||
}}
|
||||
desktopCoverSize="S"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -8,23 +8,34 @@ export const Row5 = (props: { articles: Shout[]; nodate?: boolean }) => {
|
|||
<div class="wide-container">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<ArticleCard article={props.articles[0]} settings={{ nodate: props.nodate }} />
|
||||
<ArticleCard
|
||||
article={props.articles[0]}
|
||||
settings={{ nodate: props.nodate }}
|
||||
desktopCoverSize="XS"
|
||||
/>
|
||||
<ArticleCard
|
||||
article={props.articles[1]}
|
||||
settings={{ noimage: true, withBorder: true, nodate: props.nodate }}
|
||||
desktopCoverSize="XS"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<ArticleCard
|
||||
article={props.articles[2]}
|
||||
settings={{ isBigTitle: true, nodate: props.nodate }}
|
||||
desktopCoverSize="M"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<ArticleCard article={props.articles[3]} settings={{ nodate: props.nodate }} />
|
||||
<ArticleCard
|
||||
article={props.articles[3]}
|
||||
settings={{ nodate: props.nodate }}
|
||||
desktopCoverSize="XS"
|
||||
/>
|
||||
<ArticleCard
|
||||
article={props.articles[4]}
|
||||
settings={{ noimage: true, withBorder: true, nodate: props.nodate }}
|
||||
desktopCoverSize="XS"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -20,6 +20,7 @@ export default (props: { articles: Shout[] }) => (
|
|||
isVertical: true,
|
||||
nodate: true,
|
||||
}}
|
||||
desktopCoverSize="S"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -40,7 +40,8 @@
|
|||
.authImage {
|
||||
@include font-size(1.5rem);
|
||||
|
||||
background: var(--background-color-invert) url('/auth-page.jpg') center no-repeat;
|
||||
background: var(--background-color-invert)
|
||||
url('https://images.discours.io/unsafe/1600x/production/image/auth-page.jpg') center no-repeat;
|
||||
background-size: cover;
|
||||
color: var(--default-color-invert);
|
||||
display: flex;
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { Shout, Topic } from '../../graphql/types.gen'
|
|||
|
||||
import { clsx } from 'clsx'
|
||||
import deepEqual from 'fast-deep-equal'
|
||||
import { Accessor, createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js'
|
||||
import { Accessor, createMemo, createSignal, lazy, onCleanup, onMount, Show } from 'solid-js'
|
||||
import { createStore } from 'solid-js/store'
|
||||
|
||||
import { ShoutForm, useEditorContext } from '../../context/editor'
|
||||
|
@ -14,14 +14,12 @@ import { getImageUrl } from '../../utils/getImageUrl'
|
|||
import { isDesktop } from '../../utils/media-query'
|
||||
import { slugify } from '../../utils/slugify'
|
||||
import { DropArea } from '../_shared/DropArea'
|
||||
import { GrowingTextarea } from '../_shared/GrowingTextarea'
|
||||
import { Icon } from '../_shared/Icon'
|
||||
import { Popover } from '../_shared/Popover'
|
||||
import { ImageSwiper } from '../_shared/SolidSwiper'
|
||||
import { Editor, Panel } from '../Editor'
|
||||
import { AudioUploader } from '../Editor/AudioUploader'
|
||||
import { AutoSaveNotice } from '../Editor/AutoSaveNotice'
|
||||
import SimplifiedEditor from '../Editor/SimplifiedEditor'
|
||||
import { VideoUploader } from '../Editor/VideoUploader'
|
||||
import { TableOfContents } from '../TableOfContents'
|
||||
|
||||
|
@ -29,6 +27,9 @@ import { PublishSettings } from './PublishSettings'
|
|||
|
||||
import styles from './Edit.module.scss'
|
||||
|
||||
const SimplifiedEditor = lazy(() => import('../Editor/SimplifiedEditor'))
|
||||
const GrowingTextarea = lazy(() => import('../_shared/GrowingTextarea/GrowingTextarea'))
|
||||
|
||||
type Props = {
|
||||
shout: Shout
|
||||
}
|
||||
|
|
|
@ -145,6 +145,7 @@ export const Expo = (props: Props) => {
|
|||
<ArticleCard
|
||||
article={shout}
|
||||
settings={{ nodate: true, nosubtitle: true, noAuthorLink: true }}
|
||||
desktopCoverSize="XS"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
@ -157,6 +158,7 @@ export const Expo = (props: Props) => {
|
|||
<ArticleCard
|
||||
article={shout}
|
||||
settings={{ nodate: true, nosubtitle: true, noAuthorLink: true }}
|
||||
desktopCoverSize="XS"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
.feedNavigation {
|
||||
@include font-size(1.4rem);
|
||||
|
||||
font-weight: 500;
|
||||
|
||||
h4 {
|
||||
|
|
|
@ -41,7 +41,10 @@ const getOrderBy = (by: FeedSearchParams['by']) => {
|
|||
}
|
||||
|
||||
type Props = {
|
||||
loadShouts: (options: LoadShoutsOptions) => Promise<{ hasMore: boolean; newShouts: Shout[] }>
|
||||
loadShouts: (options: LoadShoutsOptions) => Promise<{
|
||||
hasMore: boolean
|
||||
newShouts: Shout[]
|
||||
}>
|
||||
}
|
||||
|
||||
export const FeedView = (props: Props) => {
|
||||
|
@ -148,7 +151,9 @@ export const FeedView = (props: Props) => {
|
|||
<Show when={!isLoading()} fallback={<Loading />}>
|
||||
<Show when={sortedArticles().length > 0}>
|
||||
<For each={sortedArticles().slice(0, 4)}>
|
||||
{(article) => <ArticleCard article={article} settings={{ isFeedMode: true }} />}
|
||||
{(article) => (
|
||||
<ArticleCard article={article} settings={{ isFeedMode: true }} desktopCoverSize="M" />
|
||||
)}
|
||||
</For>
|
||||
|
||||
<div class={styles.asideSection}>
|
||||
|
@ -172,7 +177,9 @@ export const FeedView = (props: Props) => {
|
|||
</div>
|
||||
|
||||
<For each={sortedArticles().slice(4)}>
|
||||
{(article) => <ArticleCard article={article} settings={{ isFeedMode: true }} />}
|
||||
{(article) => (
|
||||
<ArticleCard article={article} settings={{ isFeedMode: true }} desktopCoverSize="M" />
|
||||
)}
|
||||
</For>
|
||||
</Show>
|
||||
|
||||
|
|
|
@ -105,11 +105,8 @@ export const HomeView = (props: Props) => {
|
|||
return (
|
||||
<Show when={sortedArticles().length > 0}>
|
||||
<Topics />
|
||||
|
||||
<Row5 articles={sortedArticles().slice(0, 5)} nodate={true} />
|
||||
|
||||
<Hero />
|
||||
|
||||
<Show when={sortedArticles().length > PRERENDERED_ARTICLES_COUNT}>
|
||||
<Beside
|
||||
beside={sortedArticles()[5]}
|
||||
|
@ -169,7 +166,6 @@ export const HomeView = (props: Props) => {
|
|||
<Row2 articles={sortedArticles().slice(29, 31)} nodate={true} />
|
||||
<Row3 articles={sortedArticles().slice(31, 34)} nodate={true} />
|
||||
</Show>
|
||||
|
||||
<For each={pages()}>
|
||||
{(page) => (
|
||||
<>
|
||||
|
@ -183,7 +179,6 @@ export const HomeView = (props: Props) => {
|
|||
</>
|
||||
)}
|
||||
</For>
|
||||
|
||||
<Show when={isLoadMoreButtonVisible()}>
|
||||
<p class="load-more-container">
|
||||
<button class="button" onClick={loadMore}>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { Author, Chat, Message as MessageType } from '../../graphql/types.gen'
|
||||
|
||||
import { clsx } from 'clsx'
|
||||
import { For, createSignal, Show, onMount, createEffect, createMemo } from 'solid-js'
|
||||
import { For, createSignal, Show, onMount, createEffect, createMemo, lazy } from 'solid-js'
|
||||
|
||||
import { useInbox } from '../../context/inbox'
|
||||
import { useLocalize } from '../../context/localize'
|
||||
|
@ -10,7 +10,6 @@ import { loadRecipients } from '../../stores/inbox'
|
|||
import { useRouter } from '../../stores/router'
|
||||
import { showModal } from '../../stores/ui'
|
||||
import { Icon } from '../_shared/Icon'
|
||||
import SimplifiedEditor from '../Editor/SimplifiedEditor'
|
||||
import CreateModalContent from '../Inbox/CreateModalContent'
|
||||
import DialogCard from '../Inbox/DialogCard'
|
||||
import DialogHeader from '../Inbox/DialogHeader'
|
||||
|
@ -22,6 +21,8 @@ import { Modal } from '../Nav/Modal'
|
|||
|
||||
import styles from '../../styles/Inbox.module.scss'
|
||||
|
||||
const SimplifiedEditor = lazy(() => import('../Editor/SimplifiedEditor'))
|
||||
|
||||
type InboxSearchParams = {
|
||||
initChat: string
|
||||
chat: string
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { redirectPage } from '@nanostores/router'
|
||||
import { clsx } from 'clsx'
|
||||
import { createSignal, onMount, Show } from 'solid-js'
|
||||
import { createSignal, lazy, onMount, Show } from 'solid-js'
|
||||
import { createStore } from 'solid-js/store'
|
||||
|
||||
import { ShoutForm, useEditorContext } from '../../../context/editor'
|
||||
|
@ -12,17 +12,19 @@ import { router } from '../../../stores/router'
|
|||
import { hideModal, showModal } from '../../../stores/ui'
|
||||
import { apiClient } from '../../../utils/apiClient'
|
||||
import { Button } from '../../_shared/Button'
|
||||
import { GrowingTextarea } from '../../_shared/GrowingTextarea'
|
||||
import { Icon } from '../../_shared/Icon'
|
||||
import { Image } from '../../_shared/Image'
|
||||
import { TopicSelect, UploadModalContent } from '../../Editor'
|
||||
import SimplifiedEditor, { MAX_DESCRIPTION_LIMIT } from '../../Editor/SimplifiedEditor'
|
||||
import { Modal } from '../../Nav/Modal'
|
||||
import { EMPTY_TOPIC } from '../Edit'
|
||||
|
||||
import styles from './PublishSettings.module.scss'
|
||||
import stylesBeside from '../../Feed/Beside.module.scss'
|
||||
|
||||
const SimplifiedEditor = lazy(() => import('../../Editor/SimplifiedEditor'))
|
||||
const GrowingTextarea = lazy(() => import('../../_shared/GrowingTextarea/GrowingTextarea'))
|
||||
const DESCRIPTION_MAX_LENGTH = 400
|
||||
|
||||
type Props = {
|
||||
shoutId: number
|
||||
form: ShoutForm
|
||||
|
@ -42,7 +44,7 @@ export const PublishSettings = (props: Props) => {
|
|||
if (!props.form.description) {
|
||||
const cleanFootnotes = props.form.body.replaceAll(/<footnote data-value=".*?">.*?<\/footnote>/g, '')
|
||||
const leadText = cleanFootnotes.replaceAll(/<\/?[^>]+(>|$)/gi, ' ')
|
||||
return shorten(leadText, MAX_DESCRIPTION_LIMIT).trim()
|
||||
return shorten(leadText, DESCRIPTION_MAX_LENGTH).trim()
|
||||
}
|
||||
return props.form.description
|
||||
}
|
||||
|
@ -143,7 +145,7 @@ export const PublishSettings = (props: Props) => {
|
|||
>
|
||||
<Show when={settingsForm.coverImageUrl ?? initialData.coverImageUrl}>
|
||||
<div class={styles.shoutCardCover}>
|
||||
<Image src={settingsForm.coverImageUrl} alt={initialData.title} width={1600} />
|
||||
<Image src={settingsForm.coverImageUrl} alt={initialData.title} width={800} />
|
||||
</div>
|
||||
</Show>
|
||||
<div class={styles.text}>
|
||||
|
@ -191,7 +193,7 @@ export const PublishSettings = (props: Props) => {
|
|||
label={t('Description')}
|
||||
initialContent={composeDescription()}
|
||||
onChange={(value) => setForm('description', value)}
|
||||
maxLength={MAX_DESCRIPTION_LIMIT}
|
||||
maxLength={DESCRIPTION_MAX_LENGTH}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ export const SearchView = (props: Props) => {
|
|||
<For each={sortedArticles()}>
|
||||
{(article) => (
|
||||
<div class="col-md-6">
|
||||
<ArticleCard article={article} />
|
||||
<ArticleCard article={article} desktopCoverSize="L" />
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { clsx } from 'clsx'
|
||||
import { createEffect, createSignal, Show } from 'solid-js'
|
||||
|
||||
import { ShowOnlyOnClient } from '../ShowOnlyOnClient'
|
||||
|
||||
import styles from './GrowingTextarea.module.scss'
|
||||
|
||||
type Props = {
|
||||
|
@ -15,7 +17,7 @@ type Props = {
|
|||
textAreaRef?: (el: HTMLTextAreaElement) => void
|
||||
}
|
||||
|
||||
export const GrowingTextarea = (props: Props) => {
|
||||
const GrowingTextarea = (props: Props) => {
|
||||
const [value, setValue] = createSignal<string>('')
|
||||
const [isFocused, setIsFocused] = createSignal(false)
|
||||
|
||||
|
@ -41,47 +43,51 @@ export const GrowingTextarea = (props: Props) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
class={clsx(styles.GrowingTextarea, {
|
||||
[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>
|
||||
<div class={clsx(styles.growWrap, props.class)} data-replicated-value={value()}>
|
||||
<textarea
|
||||
ref={props.textAreaRef}
|
||||
rows={1}
|
||||
maxlength={props.maxLength}
|
||||
autocomplete="off"
|
||||
class={clsx(styles.textInput, props.class)}
|
||||
value={
|
||||
props.initialValue && props.maxLength
|
||||
? props.initialValue?.slice(0, props.maxLength)
|
||||
: props.initialValue
|
||||
}
|
||||
onKeyDown={props.allowEnterKey ? handleKeyDown : null}
|
||||
onInput={(event) => handleChangeValue(event)}
|
||||
onChange={(event) => props.value(event.target.value)}
|
||||
placeholder={props.placeholder}
|
||||
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>
|
||||
<ShowOnlyOnClient>
|
||||
<div
|
||||
class={clsx(styles.GrowingTextarea, {
|
||||
[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>
|
||||
<div class={clsx(styles.growWrap, props.class)} data-replicated-value={value()}>
|
||||
<textarea
|
||||
ref={props.textAreaRef}
|
||||
rows={1}
|
||||
maxlength={props.maxLength}
|
||||
autocomplete="off"
|
||||
class={clsx(styles.textInput, props.class)}
|
||||
value={
|
||||
props.initialValue && props.maxLength
|
||||
? props.initialValue?.slice(0, props.maxLength)
|
||||
: props.initialValue
|
||||
}
|
||||
onKeyDown={props.allowEnterKey ? handleKeyDown : null}
|
||||
onInput={(event) => handleChangeValue(event)}
|
||||
onChange={(event) => props.value(event.target.value)}
|
||||
placeholder={props.placeholder}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onBlur={() => setIsFocused(false)}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
</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>
|
||||
</Show>
|
||||
</div>
|
||||
</ShowOnlyOnClient>
|
||||
)
|
||||
}
|
||||
|
||||
export default GrowingTextarea // for async load
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export { GrowingTextarea } from './GrowingTextarea'
|
|
@ -1,5 +1,6 @@
|
|||
import type { JSX } from 'solid-js'
|
||||
|
||||
import { Link } from '@solidjs/meta'
|
||||
import { splitProps } from 'solid-js'
|
||||
|
||||
import { getImageUrl } from '../../../utils/getImageUrl'
|
||||
|
@ -11,6 +12,20 @@ type Props = JSX.ImgHTMLAttributes<HTMLImageElement> & {
|
|||
|
||||
export const Image = (props: Props) => {
|
||||
const [local, others] = splitProps(props, ['src', 'alt'])
|
||||
const src = getImageUrl(local.src, { width: others.width })
|
||||
return <img src={src} alt={local.alt} {...others} />
|
||||
|
||||
const imageUrl = getImageUrl(local.src, { width: others.width })
|
||||
|
||||
const imageSrcSet = [1, 2, 3]
|
||||
.map(
|
||||
(pixelDensity) =>
|
||||
`${getImageUrl(local.src, { width: others.width * pixelDensity })} ${pixelDensity}x`,
|
||||
)
|
||||
.join(', ')
|
||||
|
||||
return (
|
||||
<>
|
||||
<Link rel="preload" as="image" imagesrcset={imageSrcSet} />
|
||||
<img src={imageUrl} alt={local.alt} srcSet={imageSrcSet} {...others} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -17,11 +17,13 @@ type Props = {
|
|||
|
||||
export const ArticleCardSwiper = (props: Props) => {
|
||||
const mainSwipeRef: { current: SwiperRef } = { current: null }
|
||||
|
||||
onMount(async () => {
|
||||
const { register } = await import('swiper/element/bundle')
|
||||
register()
|
||||
SwiperCore.use([Pagination, Navigation, Manipulation])
|
||||
})
|
||||
|
||||
return (
|
||||
<div class={clsx(styles.Swiper, styles.articleMode, styles.ArticleCardSwiper)}>
|
||||
<Show when={props.title}>
|
||||
|
@ -63,6 +65,7 @@ export const ArticleCardSwiper = (props: Props) => {
|
|||
isWithCover: true,
|
||||
nodate: true,
|
||||
}}
|
||||
desktopCoverSize="L"
|
||||
/>
|
||||
</swiper-slide>
|
||||
)}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { createFileUploader } from '@solid-primitives/upload'
|
||||
import { clsx } from 'clsx'
|
||||
import { createEffect, createSignal, For, Show, on, onMount } from 'solid-js'
|
||||
import { createEffect, createSignal, For, Show, on, onMount, lazy } from 'solid-js'
|
||||
import SwiperCore, { Manipulation, Navigation, Pagination } from 'swiper'
|
||||
|
||||
import { useLocalize } from '../../../context/localize'
|
||||
|
@ -10,7 +10,6 @@ import { composeMediaItems } from '../../../utils/composeMediaItems'
|
|||
import { getImageUrl } from '../../../utils/getImageUrl'
|
||||
import { handleImageUpload } from '../../../utils/handleImageUpload'
|
||||
import { validateFiles } from '../../../utils/validateFile'
|
||||
import SimplifiedEditor from '../../Editor/SimplifiedEditor'
|
||||
import { DropArea } from '../DropArea'
|
||||
import { Icon } from '../Icon'
|
||||
import { Image } from '../Image'
|
||||
|
@ -21,6 +20,8 @@ import { SwiperRef } from './swiper'
|
|||
|
||||
import styles from './Swiper.module.scss'
|
||||
|
||||
const SimplifiedEditor = lazy(() => import('../../Editor/SimplifiedEditor'))
|
||||
|
||||
type Props = {
|
||||
images: MediaItem[]
|
||||
editorMode?: boolean
|
||||
|
@ -178,7 +179,7 @@ export const ImageSwiper = (props: Props) => {
|
|||
// @ts-ignore
|
||||
<swiper-slide lazy="true" virtual-index={index()}>
|
||||
<div class={styles.image}>
|
||||
<Image src={slide.url} alt={slide.title} width={1600} />
|
||||
<Image src={slide.url} alt={slide.title} width={800} />
|
||||
<Show when={props.editorMode}>
|
||||
<Popover content={t('Delete')}>
|
||||
{(triggerRef: (el) => void) => (
|
||||
|
|
|
@ -48,7 +48,7 @@ export const ArticlePage = (props: PageProps) => {
|
|||
|
||||
return (
|
||||
<PageLayout
|
||||
title={props.seo.title}
|
||||
title={props.seo?.title}
|
||||
headerTitle={article()?.title || ''}
|
||||
slug={article()?.slug}
|
||||
articleBody={article()?.body}
|
||||
|
|
|
@ -57,7 +57,7 @@ export const AuthorPage = (props: PageProps) => {
|
|||
const usePrerenderedData = props.author?.slug === slug()
|
||||
|
||||
return (
|
||||
<PageLayout title={props.seo.title}>
|
||||
<PageLayout title={props.seo?.title}>
|
||||
<ReactionsProvider>
|
||||
<Show when={isLoaded()} fallback={<Loading />}>
|
||||
<AuthorView
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
import { createFileUploader } from '@solid-primitives/upload'
|
||||
import { clsx } from 'clsx'
|
||||
import deepEqual from 'fast-deep-equal'
|
||||
import { For, createSignal, Show, onMount, onCleanup, createEffect, Switch, Match } from 'solid-js'
|
||||
import { For, createSignal, Show, onMount, onCleanup, createEffect, Switch, Match, lazy } from 'solid-js'
|
||||
import { createStore } from 'solid-js/store'
|
||||
|
||||
import FloatingPanel from '../../components/_shared/FloatingPanel/FloatingPanel'
|
||||
import { GrowingTextarea } from '../../components/_shared/GrowingTextarea'
|
||||
import { Icon } from '../../components/_shared/Icon'
|
||||
import { Loading } from '../../components/_shared/Loading'
|
||||
import { PageLayout } from '../../components/_shared/PageLayout'
|
||||
import { Popover } from '../../components/_shared/Popover'
|
||||
import { SocialNetworkInput } from '../../components/_shared/SocialNetworkInput'
|
||||
import { AuthGuard } from '../../components/AuthGuard'
|
||||
import SimplifiedEditor from '../../components/Editor/SimplifiedEditor'
|
||||
import { ProfileSettingsNavigation } from '../../components/Nav/ProfileSettingsNavigation'
|
||||
import { useLocalize } from '../../context/localize'
|
||||
import { useProfileForm } from '../../context/profile'
|
||||
|
@ -26,6 +24,9 @@ import { validateUrl } from '../../utils/validateUrl'
|
|||
|
||||
import styles from './Settings.module.scss'
|
||||
|
||||
const SimplifiedEditor = lazy(() => import('../../components/Editor/SimplifiedEditor'))
|
||||
const GrowingTextarea = lazy(() => import('../../components/_shared/GrowingTextarea/GrowingTextarea'))
|
||||
|
||||
export const ProfileSettingsPage = () => {
|
||||
const { t } = useLocalize()
|
||||
const [addLinkForm, setAddLinkForm] = createSignal<boolean>(false)
|
||||
|
|
|
@ -53,7 +53,7 @@ export const TopicPage = (props: PageProps) => {
|
|||
const usePrerenderedData = props.topic?.slug === slug()
|
||||
|
||||
return (
|
||||
<PageLayout title={props.seo.title}>
|
||||
<PageLayout title={props.seo?.title}>
|
||||
<ReactionsProvider>
|
||||
<Show when={isLoaded()} fallback={<Loading />}>
|
||||
<TopicView
|
||||
|
|
|
@ -62,10 +62,10 @@ export const render = async (pageContext: PageContext) => {
|
|||
<html lang="${lng}">
|
||||
<head>
|
||||
${dangerouslySkipEscape(getAssets())}
|
||||
${dangerouslySkipEscape(generateHydrationScript())}
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">${dangerouslySkipEscape(rootContent)}</div>
|
||||
${dangerouslySkipEscape(generateHydrationScript())}
|
||||
</body>
|
||||
</html>`
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
@import 'fonts';
|
||||
@import 'globals';
|
||||
@import 'bootstrap/scss/functions';
|
||||
@import 'bootstrap/scss/variables';
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
@import 'fonts';
|
||||
@import 'bootstrap/scss/mixins/lists';
|
||||
@import 'bootstrap/scss/mixins/container';
|
||||
@import 'bootstrap/scss/mixins/utilities';
|
||||
|
|
Loading…
Reference in New Issue
Block a user