Merge branch 'router-upgrade' into feature/rating
This commit is contained in:
commit
87d08dcb75
|
@ -36,6 +36,7 @@ jobs:
|
||||||
run: npm run e2e
|
run: npm run e2e
|
||||||
env:
|
env:
|
||||||
BASE_URL: ${{ github.event.deployment_status.target_url }}
|
BASE_URL: ${{ github.event.deployment_status.target_url }}
|
||||||
|
DEBUG: pw:api
|
||||||
|
|
||||||
email-templates:
|
email-templates:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
44
.github/workflows/node-ci.yml
vendored
44
.github/workflows/node-ci.yml
vendored
|
@ -1,28 +1,54 @@
|
||||||
name: "deploy"
|
name: "CI and E2E Tests"
|
||||||
|
|
||||||
on: [push]
|
on:
|
||||||
|
push:
|
||||||
|
deployment_status:
|
||||||
|
types: [success]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
ci:
|
||||||
|
if: github.event_name == 'push'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v4
|
- uses: actions/setup-node@v4
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm i
|
run: npm i
|
||||||
|
|
||||||
- name: Install CI checks
|
- name: Install CI checks
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
- name: Check types
|
- name: Check types
|
||||||
run: npm run typecheck
|
run: npm run typecheck
|
||||||
|
|
||||||
- name: Lint with Biome
|
- name: Lint with Biome
|
||||||
run: npx @biomejs/biome check src/.
|
run: npx @biomejs/biome check src/.
|
||||||
|
|
||||||
- name: Lint styles
|
- name: Lint styles
|
||||||
run: npx stylelint **/*.{scss,css}
|
run: npx stylelint **/*.{scss,css}
|
||||||
|
|
||||||
- name: Test production build
|
- name: Test production build
|
||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
|
e2e_tests:
|
||||||
|
needs: ci
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Debug event info
|
||||||
|
run: |
|
||||||
|
echo "Event Name: ${{ github.event_name }}"
|
||||||
|
echo "Deployment Status: ${{ github.event.deployment_status.state }}"
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '18'
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install
|
||||||
|
- name: Wait for deployment to be live
|
||||||
|
run: |
|
||||||
|
echo "Waiting for Vercel deployment to be live..."
|
||||||
|
until curl -sSf https://testing3.discours.io > /dev/null; do
|
||||||
|
printf '.'
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
- name: Install Playwright and dependencies
|
||||||
|
run: npm run e2e:install
|
||||||
|
- name: Run Playwright tests
|
||||||
|
run: npm run e2e:tests:ci
|
||||||
|
env:
|
||||||
|
BASE_URL: https://testing3.discours.io
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -1,8 +1,8 @@
|
||||||
|
.devcontainer
|
||||||
dist/
|
dist/
|
||||||
node_modules/
|
node_modules/
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
pnpm-debug.log*
|
pnpm-debug.log*
|
||||||
.vscode
|
|
||||||
.env
|
.env
|
||||||
.env.production
|
.env.production
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
@ -22,6 +22,9 @@ bun.lockb
|
||||||
/blob-report/
|
/blob-report/
|
||||||
/playwright/.cache/
|
/playwright/.cache/
|
||||||
/plawright-report/
|
/plawright-report/
|
||||||
|
target
|
||||||
|
.github/dependabot.yml
|
||||||
|
|
||||||
.output
|
.output
|
||||||
.vinxi
|
.vinxi
|
||||||
|
*.pem
|
||||||
|
|
|
@ -1,34 +1,73 @@
|
||||||
{
|
{
|
||||||
"extends": ["stylelint-config-standard-scss"],
|
"defaultSeverity": "warning",
|
||||||
|
"extends": ["stylelint-config-standard-scss", "stylelint-config-recommended"],
|
||||||
"plugins": ["stylelint-order", "stylelint-scss"],
|
"plugins": ["stylelint-order", "stylelint-scss"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"keyframes-name-pattern": null,
|
"annotation-no-unknown": [
|
||||||
"declaration-block-no-redundant-longhand-properties": null,
|
|
||||||
"selector-class-pattern": null,
|
|
||||||
"no-descending-specificity": null,
|
|
||||||
"scss/function-no-unknown": null,
|
|
||||||
"scss/no-global-function-names": null,
|
|
||||||
"function-url-quotes": null,
|
|
||||||
"font-family-no-missing-generic-family-keyword": null,
|
|
||||||
"order/order": ["custom-properties", "declarations"],
|
|
||||||
"scss/dollar-variable-pattern": [
|
|
||||||
"^[a-z][a-zA-Z]+$",
|
|
||||||
{
|
|
||||||
"ignore": "global"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"selector-pseudo-class-no-unknown": [
|
|
||||||
true,
|
true,
|
||||||
{
|
{
|
||||||
"ignorePseudoClasses": ["global", "export"]
|
"ignoreAnnotations": ["default"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"at-rule-no-unknown": null,
|
||||||
|
"declaration-block-no-redundant-longhand-properties": null,
|
||||||
|
"font-family-no-missing-generic-family-keyword": null,
|
||||||
|
"function-no-unknown": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"ignoreFunctions": ["divide", "transparentize"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"function-url-quotes": null,
|
||||||
|
"keyframes-name-pattern": null,
|
||||||
|
"no-descending-specificity": null,
|
||||||
|
"order/order": [
|
||||||
|
{
|
||||||
|
"type": "at-rule",
|
||||||
|
"name": "include"
|
||||||
|
},
|
||||||
|
"custom-properties",
|
||||||
|
"declarations",
|
||||||
|
"rules"
|
||||||
|
],
|
||||||
"property-no-vendor-prefix": [
|
"property-no-vendor-prefix": [
|
||||||
true,
|
true,
|
||||||
{
|
{
|
||||||
"ignoreProperties": ["box-decoration-break"]
|
"ignoreProperties": ["box-decoration-break"]
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"scss/at-function-pattern": null,
|
||||||
|
"scss/at-mixin-pattern": null,
|
||||||
|
"scss/dollar-variable-colon-space-after": "always-single-line",
|
||||||
|
"scss/dollar-variable-colon-space-before": "never",
|
||||||
|
"scss/dollar-variable-pattern": [
|
||||||
|
"^[a-z][a-zA-Z]+$",
|
||||||
|
{
|
||||||
|
"ignore": "global"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scss/double-slash-comment-empty-line-before": [
|
||||||
|
"always",
|
||||||
|
{
|
||||||
|
"except": ["first-nested"],
|
||||||
|
"ignore": ["between-comments", "stylelint-commands"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scss/double-slash-comment-whitespace-inside": "always",
|
||||||
|
"scss/function-no-unknown": null,
|
||||||
|
"scss/no-duplicate-dollar-variables": null,
|
||||||
|
"scss/no-duplicate-mixins": null,
|
||||||
|
"scss/no-global-function-names": null,
|
||||||
|
"scss/operator-no-newline-after": null,
|
||||||
|
"scss/operator-no-newline-before": null,
|
||||||
|
"scss/operator-no-unspaced": null,
|
||||||
|
"scss/percent-placeholder-pattern": null,
|
||||||
|
"selector-class-pattern": null,
|
||||||
|
"selector-pseudo-class-no-unknown": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"ignorePseudoClasses": ["global", "export"]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
"defaultSeverity": "warning"
|
|
||||||
}
|
}
|
||||||
|
|
3
.vscode/extension.json
vendored
Normal file
3
.vscode/extension.json
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"recommendations": ["biomejs.biome", "stylelint.vscode-stylelint", "wayou.vscode-todo-highlight"]
|
||||||
|
}
|
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.organizeImports.biome": "always"
|
||||||
|
}
|
||||||
|
}
|
57
README.en.md
Normal file
57
README.en.md
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
## Development setup recommendations
|
||||||
|
|
||||||
|
### How to start
|
||||||
|
|
||||||
|
Use `bun i`, `npm i`, `pnpm i` or `yarn` to install packages.
|
||||||
|
|
||||||
|
### Config of variables
|
||||||
|
|
||||||
|
- Use `.env` file to setup your own development environment
|
||||||
|
- Env vars with prefix `PUBLIC_` are widely used in `/src/utils/config.ts`
|
||||||
|
|
||||||
|
### Useful commands
|
||||||
|
|
||||||
|
run checks, fix styles, imports, formatting and autofixable linting errors:
|
||||||
|
```
|
||||||
|
bun run typecheck
|
||||||
|
bun run fix
|
||||||
|
```
|
||||||
|
|
||||||
|
## End-to-End (E2E) Tests
|
||||||
|
|
||||||
|
This directory contains end-to-end tests. These tests are written using [Playwright](https://playwright.dev/)
|
||||||
|
|
||||||
|
### Structure
|
||||||
|
|
||||||
|
- `/tests/*`: This directory contains the test files.
|
||||||
|
- `/playwright.config.ts`: This is the configuration file for Playwright.
|
||||||
|
|
||||||
|
### Getting Started
|
||||||
|
|
||||||
|
Follow these steps:
|
||||||
|
|
||||||
|
1. **Install dependencies**: Run `npm run e2e:install` to install the necessary dependencies for running the tests.
|
||||||
|
|
||||||
|
2. **Run the tests**: After using `npm run e2e:tests`.
|
||||||
|
|
||||||
|
### Additional Information
|
||||||
|
|
||||||
|
If workers is no needed use:
|
||||||
|
- `npx playwright test --project=webkit --workers 4`
|
||||||
|
|
||||||
|
For more information on how to write tests using Playwright - [Playwright documentation](https://playwright.dev/docs/intro).
|
||||||
|
|
||||||
|
### 🚀 Tests in CI Mode
|
||||||
|
|
||||||
|
Tests are executed within a GitHub workflow. We organize our tests into two main directories:
|
||||||
|
|
||||||
|
- `tests`: Contains tests that do not require authentication.
|
||||||
|
- `tests-with-auth`: Houses tests that interact with authenticated parts of the application.
|
||||||
|
|
||||||
|
🔧 **Configuration:**
|
||||||
|
|
||||||
|
Playwright is configured to utilize the `BASE_URL` environment variable. Ensure this is properly set in your CI configuration to point to the correct environment.
|
||||||
|
|
||||||
|
📝 **Note:**
|
||||||
|
|
||||||
|
After pages have been adjusted to work with authentication, all tests should be moved to the `tests` directory to streamline the testing process.
|
62
README.md
62
README.md
|
@ -1,19 +1,61 @@
|
||||||
## How to start
|
[English](README.en.md)
|
||||||
|
|
||||||
Use Bun to manage packages.
|
## Рекомендации по настройке разработки
|
||||||
|
|
||||||
```
|
### Как начать
|
||||||
bun i
|
|
||||||
```
|
|
||||||
|
|
||||||
## Useful commands
|
Используйте `bun i`, `npm i`, `pnpm i` или `yarn`, чтобы установить пакеты.
|
||||||
|
|
||||||
run checks with your favorite package manager: npm, yarn, pnpm or bun
|
### Настройка переменных
|
||||||
|
|
||||||
|
- Используйте файл `.env` для настройки переменных собственной среды разработки.
|
||||||
|
- Переменные окружения с префиксом `PUBLIC_` широко используются в `/src/utils/config.ts`.
|
||||||
|
|
||||||
|
### Полезные команды
|
||||||
|
|
||||||
|
Запуск проверки соответствия типов и автоматически исправить ошибки стилей, порядок импорта, форматирование:
|
||||||
|
|
||||||
```
|
```
|
||||||
bun run typecheck
|
bun run typecheck
|
||||||
```
|
|
||||||
fix styles, imports, formatting and autofixable linting errors:
|
|
||||||
```
|
|
||||||
bun run fix
|
bun run fix
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## End-to-End (E2E) тесты
|
||||||
|
|
||||||
|
End-to-end тесты написаны с использованием [Playwright](https://playwright.dev/).
|
||||||
|
|
||||||
|
### Структура
|
||||||
|
|
||||||
|
- `/tests/*`: содержит файлы тестов
|
||||||
|
- `/playwright.config.ts`: конфиг для Playwright
|
||||||
|
|
||||||
|
### Начало работы
|
||||||
|
|
||||||
|
Следуйте этим шагам:
|
||||||
|
|
||||||
|
1. **Установите зависимости**: Запустите `npm run e2e:install`, чтобы установить необходимые зависимости для выполнения тестов.
|
||||||
|
|
||||||
|
2. **Запустите тесты**: После установки зависимостей используйте `npm run e2e:tests`.
|
||||||
|
|
||||||
|
### Дополнительная информация
|
||||||
|
|
||||||
|
Для параллельного исполнения:
|
||||||
|
- `npx playwright test --project=webkit --workers 4`
|
||||||
|
|
||||||
|
Для получения дополнительной информации о написании тестов с использованием Playwright - [Документация Playwright](https://playwright.dev/docs/intro).
|
||||||
|
|
||||||
|
### 🚀 Тесты в режиме CI
|
||||||
|
|
||||||
|
Тесты выполняются в рамках GitHub workflow. Мы организуем наши тесты в две основные директории:
|
||||||
|
|
||||||
|
- `tests`: Содержит тесты, которые не требуют аутентификации.
|
||||||
|
- `tests-with-auth`: Содержит тесты, которые взаимодействуют с аутентифицированными частями приложения.
|
||||||
|
|
||||||
|
🔧 **Конфигурация:**
|
||||||
|
|
||||||
|
Playwright настроен на использование переменной окружения `BASE_URL`. Убедитесь, что она правильно установлена в вашей конфигурации CI для указания на правильную среду.
|
||||||
|
|
||||||
|
📝 **Примечание:**
|
||||||
|
|
||||||
|
После того как страницы были настроены для работы с аутентификацией, все тесты должны быть перемещены в директорию `tests` для упрощения процесса тестирования.
|
||||||
|
|
|
@ -1,15 +1,33 @@
|
||||||
import { SolidStartInlineConfig, defineConfig } from '@solidjs/start/config'
|
import { SolidStartInlineConfig, defineConfig } from '@solidjs/start/config'
|
||||||
import { nodePolyfills } from 'vite-plugin-node-polyfills'
|
import { CSSOptions } from 'vite'
|
||||||
|
// import { visualizer } from 'rollup-plugin-visualizer'
|
||||||
|
import mkcert from 'vite-plugin-mkcert'
|
||||||
|
import { PolyfillOptions, nodePolyfills } from 'vite-plugin-node-polyfills'
|
||||||
import sassDts from 'vite-plugin-sass-dts'
|
import sassDts from 'vite-plugin-sass-dts'
|
||||||
|
|
||||||
const isVercel = Boolean(process?.env.VERCEL)
|
const isVercel = Boolean(process?.env.VERCEL)
|
||||||
const isBun = Boolean(process.env.BUN)
|
const isBun = Boolean(process.env.BUN)
|
||||||
|
|
||||||
|
console.info(`[app.config] build for ${isVercel ? 'vercel' : isBun ? 'bun' : 'node'}!`)
|
||||||
|
|
||||||
|
const polyfillOptions = {
|
||||||
|
include: ['path', 'stream', 'util'],
|
||||||
|
exclude: ['http'],
|
||||||
|
globals: {
|
||||||
|
Buffer: true
|
||||||
|
},
|
||||||
|
overrides: {
|
||||||
|
fs: 'memfs'
|
||||||
|
},
|
||||||
|
protocolImports: true
|
||||||
|
} as PolyfillOptions
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
ssr: true,
|
ssr: true,
|
||||||
server: {
|
server: {
|
||||||
preset: isVercel ? 'vercel_edge' : isBun ? 'bun' : 'node',
|
preset: isVercel ? 'vercel_edge' : isBun ? 'bun' : 'node',
|
||||||
port: 3000
|
port: 3000,
|
||||||
|
https: true
|
||||||
},
|
},
|
||||||
devOverlay: true,
|
devOverlay: true,
|
||||||
build: {
|
build: {
|
||||||
|
@ -18,31 +36,14 @@ export default defineConfig({
|
||||||
},
|
},
|
||||||
vite: {
|
vite: {
|
||||||
envPrefix: 'PUBLIC_',
|
envPrefix: 'PUBLIC_',
|
||||||
plugins: [
|
plugins: [!isVercel && mkcert(), nodePolyfills(polyfillOptions), sassDts()],
|
||||||
nodePolyfills({
|
|
||||||
include: ['path', 'stream', 'util'],
|
|
||||||
exclude: ['http'],
|
|
||||||
globals: {
|
|
||||||
Buffer: true
|
|
||||||
},
|
|
||||||
overrides: {
|
|
||||||
fs: 'memfs'
|
|
||||||
},
|
|
||||||
protocolImports: true
|
|
||||||
}),
|
|
||||||
sassDts()
|
|
||||||
],
|
|
||||||
css: {
|
css: {
|
||||||
preprocessorOptions: {
|
preprocessorOptions: {
|
||||||
scss: {
|
scss: {
|
||||||
additionalData: '@import "src/styles/imports";\n',
|
additionalData: '@import "src/styles/imports";\n',
|
||||||
includePaths: ['./public', './src/styles']
|
includePaths: ['./public', './src/styles']
|
||||||
}
|
}
|
||||||
}
|
} as CSSOptions['preprocessorOptions']
|
||||||
},
|
|
||||||
build: {
|
|
||||||
chunkSizeWarningLimit: 1024,
|
|
||||||
target: 'esnext'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} as SolidStartInlineConfig)
|
} as SolidStartInlineConfig)
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
if [ "$VERCEL_GIT_COMMIT_REF" = "router-upgrade" ] || [ "$VERCEL_GIT_COMMIT_REF" = "feature/rating" ]; then
|
|
||||||
echo "Building on solid start"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "Not on solid start"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
|
@ -1,66 +0,0 @@
|
||||||
@startuml
|
|
||||||
actor User
|
|
||||||
participant Browser
|
|
||||||
participant Vercel
|
|
||||||
participant article.page.server.ts
|
|
||||||
participant Solid
|
|
||||||
participant Store
|
|
||||||
|
|
||||||
User -> Browser: discours.io
|
|
||||||
activate Browser
|
|
||||||
Browser -> Vercel: GET <slug>
|
|
||||||
activate Vercel
|
|
||||||
Vercel -> article.page.server.ts: render
|
|
||||||
activate article.page.server.ts
|
|
||||||
article.page.server.ts -> apiClient: getArticle({ slug })
|
|
||||||
activate apiClient
|
|
||||||
apiClient -> DB: query: articleBySlug
|
|
||||||
activate DB
|
|
||||||
DB --> apiClient: response
|
|
||||||
deactivate DB
|
|
||||||
apiClient --> article.page.server.ts: article data
|
|
||||||
deactivate apiClient
|
|
||||||
article.page.server.ts -> Solid: render <ArticlePage article={article} />
|
|
||||||
activate Solid
|
|
||||||
Solid -> Store: useCurrentArticleStore(article)
|
|
||||||
activate Store
|
|
||||||
Store -> Store: create store with initial data (server)
|
|
||||||
Store --> Solid: currentArticle
|
|
||||||
deactivate Store
|
|
||||||
Solid -> Solid: render component
|
|
||||||
Solid --> article.page.server.ts: rendered component
|
|
||||||
deactivate Solid
|
|
||||||
article.page.server.ts --> Vercel: rendered page
|
|
||||||
Vercel -> Vercel: save rendered page to CDN
|
|
||||||
deactivate article.page.server.ts
|
|
||||||
Vercel --> Browser: rendered page
|
|
||||||
deactivate Vercel
|
|
||||||
Browser --> User: rendered page
|
|
||||||
deactivate Browser
|
|
||||||
Browser -> Browser: load client scripts
|
|
||||||
Browser -> Solid: render <ArticlePage article={article} />
|
|
||||||
Solid -> Store: useCurrentArticleStore(article)
|
|
||||||
activate Store
|
|
||||||
Store -> Store: create store with initial data (client)
|
|
||||||
Store --> Solid: currentArticle
|
|
||||||
deactivate Store
|
|
||||||
Solid -> Solid: render component (no changes)
|
|
||||||
Solid -> Solid: onMount
|
|
||||||
Solid -> Store: loadArticleComments
|
|
||||||
activate Store
|
|
||||||
Store -> apiClient: getArticleComments
|
|
||||||
activate apiClient
|
|
||||||
apiClient -> DB: query: getReactions
|
|
||||||
activate DB
|
|
||||||
DB --> apiClient: response
|
|
||||||
deactivate DB
|
|
||||||
apiClient --> Store: comments data
|
|
||||||
deactivate apiClient
|
|
||||||
Store -> Store: update store
|
|
||||||
Store --> Solid: store updated
|
|
||||||
deactivate Store
|
|
||||||
Solid -> Solid: render comments
|
|
||||||
Solid --> Browser: rendered comments
|
|
||||||
Browser --> User: comments
|
|
||||||
@enduml
|
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
@startuml
|
|
||||||
actor User
|
|
||||||
participant Browser
|
|
||||||
participant Server
|
|
||||||
|
|
||||||
User -> Browser: discours.io
|
|
||||||
activate Browser
|
|
||||||
Browser -> Server: GET\nquery { lng }\ncookies { lng }
|
|
||||||
opt lng in query
|
|
||||||
Server -> Server: lng = lng from query
|
|
||||||
else no lng in query
|
|
||||||
opt lng in cookies
|
|
||||||
Server -> Server: lng = lng from cookies
|
|
||||||
else no lng in cookies
|
|
||||||
Server -> Server: lng = 'ru'
|
|
||||||
end opt
|
|
||||||
end opt
|
|
||||||
note right
|
|
||||||
_dafault.page.server.ts render
|
|
||||||
end note
|
|
||||||
|
|
||||||
opt i18next is not initialized
|
|
||||||
Server -> Server: initialize i18next with lng
|
|
||||||
else i18next not initialized
|
|
||||||
Server -> Server: change i18next language to lng
|
|
||||||
end opt
|
|
||||||
note right
|
|
||||||
all resources loaded synchronously
|
|
||||||
end note
|
|
||||||
Server --> Browser: pageContext { lng }
|
|
||||||
Browser -> Browser: init client side i18next with http backend
|
|
||||||
activate Browser
|
|
||||||
Browser -> Server: get translations for current language
|
|
||||||
Server --> Browser: translations JSON
|
|
||||||
deactivate Browser
|
|
||||||
Browser -> Browser: render page
|
|
||||||
Browser --> User: rendered page
|
|
||||||
deactivate Browser
|
|
||||||
@enduml
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
@startuml
|
|
||||||
actor User
|
|
||||||
participant Browser
|
|
||||||
participant Server
|
|
||||||
|
|
||||||
User -> Browser: discours.io
|
|
||||||
activate Browser
|
|
||||||
Browser -> Server: GET
|
|
||||||
activate Server
|
|
||||||
Server -> Server: resolve route
|
|
||||||
note right
|
|
||||||
based on routes from
|
|
||||||
*.page.route.ts files
|
|
||||||
end note
|
|
||||||
Server -> Server: some.page.server.ts onBeforeRender
|
|
||||||
Server -> Server: _default.page.server.tsx render
|
|
||||||
Server --> Browser: pageContent
|
|
||||||
deactivate Server
|
|
||||||
Browser -> Browser: _default.page.client.tsx render(pageContext)
|
|
||||||
|
|
||||||
Browser --> User: rendered page
|
|
||||||
deactivate Browser
|
|
||||||
@enduml
|
|
||||||
|
|
3315
package-lock.json
generated
3315
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
121
package.json
121
package.json
|
@ -2,71 +2,73 @@
|
||||||
"name": "discoursio-webapp",
|
"name": "discoursio-webapp",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.9.5",
|
"version": "0.9.5",
|
||||||
"contributors": [],
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vinxi dev",
|
"dev": "vinxi dev",
|
||||||
"build": "vinxi build",
|
"build": "vinxi build",
|
||||||
"start": "vinxi start",
|
"start": "vinxi start",
|
||||||
"codegen": "graphql-codegen",
|
"codegen": "graphql-codegen",
|
||||||
"e2e": "npx playwright test --project=webkit",
|
"e2e": "E2E=1 npm run e2e:tests",
|
||||||
"fix": "npx @biomejs/biome check src/. --write && stylelint **/*.{scss,css} --fix",
|
"e2e:tests": "npx playwright test --project=webkit",
|
||||||
|
"e2e:tests:ci": "CI=true npx playwright test --project=webkit",
|
||||||
|
"e2e:install": "npx playwright install webkit && npx playwright install-deps ",
|
||||||
|
"fix": "npx @biomejs/biome check . --fix && stylelint **/*.{scss,css} --fix",
|
||||||
"format": "npx @biomejs/biome format src/. --write",
|
"format": "npx @biomejs/biome format src/. --write",
|
||||||
"postinstall": "npm run codegen && npx patch-package",
|
"postinstall": "npm run codegen && npx patch-package",
|
||||||
"typecheck": "tsc --noEmit"
|
"typecheck": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@authorizerdev/authorizer-js": "^2.0.3",
|
"@authorizerdev/authorizer-js": "^2.0.3",
|
||||||
"@biomejs/biome": "^1.8.2",
|
"@biomejs/biome": "^1.8.3",
|
||||||
"@graphql-codegen/cli": "^5.0.2",
|
"@graphql-codegen/cli": "^5.0.2",
|
||||||
"@graphql-codegen/typescript": "^4.0.7",
|
"@graphql-codegen/typescript": "^4.0.9",
|
||||||
"@graphql-codegen/typescript-operations": "^4.2.1",
|
"@graphql-codegen/typescript-operations": "^4.2.3",
|
||||||
"@graphql-codegen/typescript-urql": "^4.0.0",
|
"@graphql-codegen/typescript-urql": "^4.0.0",
|
||||||
"@hocuspocus/provider": "^2.13.2",
|
"@hocuspocus/provider": "^2.13.5",
|
||||||
"@playwright/test": "^1.44.1",
|
"@playwright/test": "^1.45.2",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"@solid-primitives/media": "^2.2.9",
|
"@solid-primitives/media": "^2.2.9",
|
||||||
"@solid-primitives/memo": "^1.3.8",
|
"@solid-primitives/memo": "^1.3.9",
|
||||||
"@solid-primitives/pagination": "^0.3.0",
|
"@solid-primitives/pagination": "^0.3.0",
|
||||||
"@solid-primitives/script-loader": "^2.2.0",
|
"@solid-primitives/script-loader": "^2.2.0",
|
||||||
"@solid-primitives/share": "^2.0.6",
|
"@solid-primitives/share": "^2.0.6",
|
||||||
"@solid-primitives/storage": "^3.7.1",
|
"@solid-primitives/storage": "^3.8.0",
|
||||||
"@solid-primitives/upload": "^0.0.117",
|
"@solid-primitives/upload": "^0.0.117",
|
||||||
"@solidjs/meta": "^0.29.4",
|
"@solidjs/meta": "^0.29.4",
|
||||||
"@solidjs/router": "^0.13.6",
|
"@solidjs/router": "^0.14.1",
|
||||||
"@solidjs/start": "^1.0.2",
|
"@solidjs/start": "^1.0.6",
|
||||||
"@tiptap/core": "^2.4.0",
|
"@tiptap/core": "^2.5.4",
|
||||||
"@tiptap/extension-blockquote": "^2.4.0",
|
"@tiptap/extension-blockquote": "^2.5.4",
|
||||||
"@tiptap/extension-bold": "^2.4.0",
|
"@tiptap/extension-bold": "^2.5.4",
|
||||||
"@tiptap/extension-bubble-menu": "^2.4.0",
|
"@tiptap/extension-bubble-menu": "^2.5.4",
|
||||||
"@tiptap/extension-bullet-list": "^2.4.0",
|
"@tiptap/extension-bullet-list": "^2.5.4",
|
||||||
"@tiptap/extension-character-count": "^2.4.0",
|
"@tiptap/extension-character-count": "^2.5.4",
|
||||||
"@tiptap/extension-collaboration": "^2.4.0",
|
"@tiptap/extension-collaboration": "^2.5.4",
|
||||||
"@tiptap/extension-collaboration-cursor": "^2.4.0",
|
"@tiptap/extension-collaboration-cursor": "^2.5.4",
|
||||||
"@tiptap/extension-document": "^2.4.0",
|
"@tiptap/extension-document": "^2.5.4",
|
||||||
"@tiptap/extension-dropcursor": "^2.4.0",
|
"@tiptap/extension-dropcursor": "^2.5.4",
|
||||||
"@tiptap/extension-floating-menu": "^2.4.0",
|
"@tiptap/extension-floating-menu": "^2.5.4",
|
||||||
"@tiptap/extension-focus": "^2.4.0",
|
"@tiptap/extension-focus": "^2.5.4",
|
||||||
"@tiptap/extension-gapcursor": "^2.4.0",
|
"@tiptap/extension-gapcursor": "^2.5.4",
|
||||||
"@tiptap/extension-hard-break": "^2.4.0",
|
"@tiptap/extension-hard-break": "^2.5.4",
|
||||||
"@tiptap/extension-heading": "^2.4.0",
|
"@tiptap/extension-heading": "^2.5.4",
|
||||||
"@tiptap/extension-highlight": "^2.4.0",
|
"@tiptap/extension-highlight": "^2.5.4",
|
||||||
"@tiptap/extension-history": "^2.4.0",
|
"@tiptap/extension-history": "^2.5.4",
|
||||||
"@tiptap/extension-horizontal-rule": "^2.4.0",
|
"@tiptap/extension-horizontal-rule": "^2.5.4",
|
||||||
"@tiptap/extension-image": "^2.4.0",
|
"@tiptap/extension-image": "^2.5.4",
|
||||||
"@tiptap/extension-italic": "^2.4.0",
|
"@tiptap/extension-italic": "^2.5.4",
|
||||||
"@tiptap/extension-link": "^2.4.0",
|
"@tiptap/extension-link": "^2.5.4",
|
||||||
"@tiptap/extension-list-item": "^2.4.0",
|
"@tiptap/extension-list-item": "^2.5.4",
|
||||||
"@tiptap/extension-ordered-list": "^2.4.0",
|
"@tiptap/extension-ordered-list": "^2.5.4",
|
||||||
"@tiptap/extension-paragraph": "^2.4.0",
|
"@tiptap/extension-paragraph": "^2.5.4",
|
||||||
"@tiptap/extension-placeholder": "^2.4.0",
|
"@tiptap/extension-placeholder": "^2.5.4",
|
||||||
"@tiptap/extension-strike": "^2.4.0",
|
"@tiptap/extension-strike": "^2.5.4",
|
||||||
"@tiptap/extension-text": "^2.4.0",
|
"@tiptap/extension-text": "^2.5.4",
|
||||||
"@tiptap/extension-underline": "^2.4.0",
|
"@tiptap/extension-underline": "^2.5.4",
|
||||||
"@tiptap/extension-youtube": "^2.4.0",
|
"@tiptap/extension-youtube": "^2.5.4",
|
||||||
"@types/cookie": "^0.6.0",
|
"@types/cookie": "^0.6.0",
|
||||||
"@types/cookie-signature": "^1.1.2",
|
"@types/cookie-signature": "^1.1.2",
|
||||||
"@types/node": "^20.14.8",
|
"@types/node": "^20.14.11",
|
||||||
"@types/throttle-debounce": "^5.0.2",
|
"@types/throttle-debounce": "^5.0.2",
|
||||||
"@urql/core": "^5.0.4",
|
"@urql/core": "^5.0.4",
|
||||||
"bootstrap": "^5.3.3",
|
"bootstrap": "^5.3.3",
|
||||||
|
@ -77,33 +79,36 @@
|
||||||
"extended-eventsource": "^1.4.9",
|
"extended-eventsource": "^1.4.9",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"graphql": "^16.9.0",
|
"graphql": "^16.9.0",
|
||||||
"i18next": "^23.11.5",
|
"i18next": "^23.12.2",
|
||||||
"i18next-http-backend": "^2.5.2",
|
"i18next-http-backend": "^2.5.2",
|
||||||
"i18next-icu": "^2.3.0",
|
"i18next-icu": "^2.3.0",
|
||||||
"intl-messageformat": "^10.5.14",
|
"intl-messageformat": "^10.5.14",
|
||||||
"javascript-time-ago": "^2.5.10",
|
"javascript-time-ago": "^2.5.10",
|
||||||
"patch-package": "^8.0.0",
|
"patch-package": "^8.0.0",
|
||||||
"prosemirror-history": "^1.4.0",
|
"prosemirror-history": "^1.4.1",
|
||||||
"prosemirror-trailing-node": "^2.0.8",
|
"prosemirror-trailing-node": "^2.0.9",
|
||||||
"prosemirror-view": "^1.33.8",
|
"prosemirror-view": "^1.33.9",
|
||||||
"sass": "^1.77.6",
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
"solid-js": "1.8.17",
|
"sass": "1.76.0",
|
||||||
|
"solid-js": "^1.8.18",
|
||||||
"solid-popper": "^0.3.0",
|
"solid-popper": "^0.3.0",
|
||||||
"solid-tiptap": "0.7.0",
|
"solid-tiptap": "0.7.0",
|
||||||
"solid-transition-group": "^0.2.3",
|
"solid-transition-group": "^0.2.3",
|
||||||
"stylelint": "^16.6.1",
|
"stylelint": "^16.7.0",
|
||||||
|
"stylelint-config-recommended": "^14.0.1",
|
||||||
"stylelint-config-standard-scss": "^13.1.0",
|
"stylelint-config-standard-scss": "^13.1.0",
|
||||||
"stylelint-order": "^6.0.4",
|
"stylelint-order": "^6.0.4",
|
||||||
"stylelint-scss": "^6.3.2",
|
"stylelint-scss": "^6.4.1",
|
||||||
"swiper": "^11.1.4",
|
"swiper": "^11.1.5",
|
||||||
"throttle-debounce": "^5.0.2",
|
"throttle-debounce": "^5.0.2",
|
||||||
"tslib": "^2.6.3",
|
"tslib": "^2.6.3",
|
||||||
"typescript": "^5.5.2",
|
"typescript": "^5.5.3",
|
||||||
"typograf": "^7.4.1",
|
"typograf": "^7.4.1",
|
||||||
"uniqolor": "^1.1.1",
|
"uniqolor": "^1.1.1",
|
||||||
"vinxi": "^0.3.12",
|
"vinxi": "^0.4.1",
|
||||||
|
"vite-plugin-mkcert": "^1.17.5",
|
||||||
"vite-plugin-node-polyfills": "^0.22.0",
|
"vite-plugin-node-polyfills": "^0.22.0",
|
||||||
"vite-plugin-sass-dts": "^1.3.22",
|
"vite-plugin-sass-dts": "^1.3.24",
|
||||||
"y-prosemirror": "1.2.9",
|
"y-prosemirror": "1.2.9",
|
||||||
"yjs": "13.6.18"
|
"yjs": "13.6.18"
|
||||||
},
|
},
|
||||||
|
@ -111,13 +116,13 @@
|
||||||
"yjs": "13.6.18",
|
"yjs": "13.6.18",
|
||||||
"y-prosemirror": "1.2.9"
|
"y-prosemirror": "1.2.9"
|
||||||
},
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 20"
|
||||||
|
},
|
||||||
"trustedDependencies": ["@biomejs/biome", "esbuild", "protobufjs"],
|
"trustedDependencies": ["@biomejs/biome", "esbuild", "protobufjs"],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"idb": "^8.0.0",
|
"idb": "^8.0.0",
|
||||||
"mailgun.js": "^10.2.1"
|
"mailgun.js": "^10.2.3"
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "20.x"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,10 @@ import { defineConfig, devices } from '@playwright/test'
|
||||||
* See https://playwright.dev/docs/test-configuration.
|
* See https://playwright.dev/docs/test-configuration.
|
||||||
*/
|
*/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
/* Directory to search for tests */
|
||||||
testDir: './tests',
|
testDir: './tests',
|
||||||
/* Run tests in files in parallel */
|
/* Run tests in files in parallel */
|
||||||
fullyParallel: true,
|
fullyParallel: false,
|
||||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
forbidOnly: !!process.env.CI,
|
forbidOnly: !!process.env.CI,
|
||||||
/* Retry on CI only */
|
/* Retry on CI only */
|
||||||
|
@ -20,28 +21,23 @@ export default defineConfig({
|
||||||
/* Opt out of parallel tests on CI. */
|
/* Opt out of parallel tests on CI. */
|
||||||
workers: process.env.CI ? 1 : undefined,
|
workers: process.env.CI ? 1 : undefined,
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: 'html',
|
reporter: 'list',
|
||||||
|
/* Timeout for each test */
|
||||||
|
timeout: 40000,
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
use: {
|
use: {
|
||||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
// baseURL: 'http://127.0.0.1:3000',
|
baseURL: process.env.BASE_URL || 'https://localhost:3000',
|
||||||
|
/* Headless */
|
||||||
|
headless: true,
|
||||||
|
/* Ignode SSL certificates */
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||||
trace: 'on-first-retry'
|
trace: 'on-first-retry'
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Configure projects for major browsers */
|
/* Configure projects for major browsers */
|
||||||
projects: [
|
projects: [
|
||||||
{
|
|
||||||
name: 'chromium',
|
|
||||||
use: { ...devices['Desktop Chrome'] }
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: 'firefox',
|
|
||||||
use: { ...devices['Desktop Firefox'] }
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'webkit',
|
name: 'webkit',
|
||||||
use: { ...devices['Desktop Safari'] }
|
use: { ...devices['Desktop Safari'] }
|
||||||
|
@ -66,12 +62,17 @@ export default defineConfig({
|
||||||
// name: 'Google Chrome',
|
// name: 'Google Chrome',
|
||||||
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||||
// },
|
// },
|
||||||
]
|
],
|
||||||
|
|
||||||
/* Run local dev server before starting the tests */
|
/* Run local dev server before starting the tests */
|
||||||
//webServer: {
|
/* If process env CI is set to false */
|
||||||
// command: 'npm run dev',
|
webServer: process.env.CI
|
||||||
// url: 'https://localhost:3000',
|
? undefined
|
||||||
// reuseExistingServer: !process.env.CI,
|
: {
|
||||||
//},
|
command: 'npm run dev',
|
||||||
|
url: 'http://localhost:3000',
|
||||||
|
ignoreHTTPSErrors: true,
|
||||||
|
reuseExistingServer: !process.env.CI,
|
||||||
|
timeout: 5 * 60 * 1000
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
Before Width: | Height: | Size: 714 B After Width: | Height: | Size: 714 B |
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B |
Before Width: | Height: | Size: 290 B After Width: | Height: | Size: 290 B |
|
@ -1,551 +0,0 @@
|
||||||
{
|
|
||||||
"A guide to horizontal editorial: how an open journal works": "A guide to horizontal editorial: how an open journal works",
|
|
||||||
"About": "About",
|
|
||||||
"About the project": "About the project",
|
|
||||||
"actions": "actions",
|
|
||||||
"Add": "Add",
|
|
||||||
"Add a few topics so that the reader knows what your content is about and can find it on pages of topics that interest them. Topics can be swapped, the first topic becomes the title": "Add a few topics so that the reader knows what your content is about and can find it on pages of topics that interest them. Topics can be swapped, the first topic becomes the title",
|
|
||||||
"Add a link or click plus to embed media": "Add a link or click plus to embed media",
|
|
||||||
"Add an embed widget": "Add an embed widget",
|
|
||||||
"Add another image": "Add another image",
|
|
||||||
"Add audio": "Add audio",
|
|
||||||
"Add blockquote": "Add blockquote",
|
|
||||||
"Add comment": "Comment",
|
|
||||||
"Add cover": "Add cover",
|
|
||||||
"Add image": "Add image",
|
|
||||||
"Add images": "Add images",
|
|
||||||
"Add intro": "Add intro",
|
|
||||||
"add link": "add link",
|
|
||||||
"Add link": "Add link",
|
|
||||||
"Add rule": "Add rule",
|
|
||||||
"Add signature": "Add signature",
|
|
||||||
"Add subtitle": "Add subtitle",
|
|
||||||
"Add url": "Add url",
|
|
||||||
"Address on Discours": "Address on Discours",
|
|
||||||
"Album name": "Название aльбома",
|
|
||||||
"Alignment center": "Alignment center",
|
|
||||||
"Alignment left": "Alignment left",
|
|
||||||
"Alignment right": "Alignment right",
|
|
||||||
"All": "All",
|
|
||||||
"All articles": "All articles",
|
|
||||||
"All authors": "All authors",
|
|
||||||
"All posts": "All posts",
|
|
||||||
"all topics": "all topics",
|
|
||||||
"All topics": "All topics",
|
|
||||||
"Almost done! Check your email.": "Almost done! Just checking your email.",
|
|
||||||
"and some more authors": "{restUsersCount, plural, =0 {} one { and one more user} other { and more {restUsersCount} users}}",
|
|
||||||
"Anything else": "Anything else",
|
|
||||||
"Are you sure you want to delete this comment?": "Are you sure you want to delete this comment?",
|
|
||||||
"Are you sure you want to delete this draft?": "Are you sure you want to delete this draft?",
|
|
||||||
"Are you sure you want to to proceed the action?": "Are you sure you want to to proceed the action?",
|
|
||||||
"Art": "Art",
|
|
||||||
"article": "article",
|
|
||||||
"Artist": "Artist",
|
|
||||||
"Artworks": "Artworks",
|
|
||||||
"Audio": "Audio",
|
|
||||||
"author": "author",
|
|
||||||
"Author": "Author",
|
|
||||||
"authors": "authors",
|
|
||||||
"Authors": "Authors",
|
|
||||||
"Autotypograph": "Autotypograph",
|
|
||||||
"Back": "Back",
|
|
||||||
"Back to editor": "Back to editor",
|
|
||||||
"Back to main page": "Back to main page",
|
|
||||||
"back to menu": "back to menu",
|
|
||||||
"Be the first to rate": "Be the first to rate",
|
|
||||||
"Become an author": "Become an author",
|
|
||||||
"bold": "bold",
|
|
||||||
"Bold": "Bold",
|
|
||||||
"Bookmarked": "Saved",
|
|
||||||
"bookmarks": "bookmarks",
|
|
||||||
"Bookmarks": "Bookmarks",
|
|
||||||
"Bullet list": "Bullet list",
|
|
||||||
"By alphabet": "By alphabet",
|
|
||||||
"By authors": "By authors",
|
|
||||||
"By name": "By name",
|
|
||||||
"By popularity": "By popularity",
|
|
||||||
"By rating": "By popularity",
|
|
||||||
"By relevance": "By relevance",
|
|
||||||
"By shouts": "By publications",
|
|
||||||
"By signing up you agree with our": "By signing up you agree with our",
|
|
||||||
"By time": "By time",
|
|
||||||
"By title": "By title",
|
|
||||||
"By updates": "By updates",
|
|
||||||
"By views": "By views",
|
|
||||||
"Can make any changes, accept or reject suggestions, and share access with others": "Can make any changes, accept or reject suggestions, and share access with others",
|
|
||||||
"Can offer edits and comments, but cannot edit the post or share access with others": "Can offer edits and comments, but cannot edit the post or share access with others",
|
|
||||||
"Can write and edit text directly, and accept or reject suggestions from others": "Can write and edit text directly, and accept or reject suggestions from others",
|
|
||||||
"cancel": "cancel",
|
|
||||||
"Cancel": "Cancel",
|
|
||||||
"Cancel changes": "Cancel changes",
|
|
||||||
"Change password": "Change password",
|
|
||||||
"Characters": "Знаков",
|
|
||||||
"Chat Title": "Chat Title",
|
|
||||||
"Choose a post type": "Choose a post type",
|
|
||||||
"Choose a title image for the article. You can immediately see how the publication card will look like.": "Choose a title image for the article. You can immediately see how the publication card will look like.",
|
|
||||||
"Choose who you want to write to": "Choose who you want to write to",
|
|
||||||
"Close": "Close",
|
|
||||||
"Co-author": "Co-author",
|
|
||||||
"Collaborate": "Help Edit",
|
|
||||||
"Collaborators": "Collaborators",
|
|
||||||
"collections": "collections",
|
|
||||||
"Collections": "Collections",
|
|
||||||
"Come up with a subtitle for your story": "Come up with a subtitle for your story",
|
|
||||||
"Come up with a title for your story": "Come up with a title for your story",
|
|
||||||
"Coming soon": "Coming soon",
|
|
||||||
"Comment successfully deleted": "Comment successfully deleted",
|
|
||||||
"Commentator": "Commentator",
|
|
||||||
"Commenting": "Commenting",
|
|
||||||
"Comments": "Comments",
|
|
||||||
"Common feed": "All",
|
|
||||||
"Communities": "Communities",
|
|
||||||
"community": "community",
|
|
||||||
"Community Discussion Rules": "Community Discussion Rules",
|
|
||||||
"Community Principles": "Community Principles",
|
|
||||||
"Community values and rules of engagement for the open editorial team": "Community values and rules of engagement for the open editorial team",
|
|
||||||
"Confirm": "Confirm",
|
|
||||||
"Confirm your new password": "Confirm your new password",
|
|
||||||
"Connect": "Connect",
|
|
||||||
"Contents": "Contents",
|
|
||||||
"Contribute to free samizdat. Support Discours - an independent non-profit publication that works only for you. Become a pillar of the open newsroom": "Contribute to free samizdat. Support Discours - an independent non-profit publication that works only for you. Become a pillar of the open newsroom",
|
|
||||||
"Cooperate": "Cooperate",
|
|
||||||
"Copy": "Copy",
|
|
||||||
"Copy link": "Copy link",
|
|
||||||
"Corrections history": "Corrections history",
|
|
||||||
"Create account": "Create an account",
|
|
||||||
"Create an account to add to your bookmarks": "Create an account to add to your bookmarks",
|
|
||||||
"Create an account to participate in discussions": "Create an account to participate in discussions",
|
|
||||||
"Create an account to publish articles": "Create an account to publish articles",
|
|
||||||
"Create an account to subscribe": "Create an account to subscribe",
|
|
||||||
"Create an account to subscribe to new publications": "Create an account to subscribe to new publications",
|
|
||||||
"Create an account to vote": "Create an account to vote",
|
|
||||||
"Create Chat": "Create Chat",
|
|
||||||
"Create gallery": "Create gallery",
|
|
||||||
"Create Group": "Create a group",
|
|
||||||
"Create post": "Create post",
|
|
||||||
"Create video": "Create video",
|
|
||||||
"Crop image": "Crop image",
|
|
||||||
"Culture": "Culture",
|
|
||||||
"Current password": "Current password",
|
|
||||||
"Date of Birth": "Date of Birth",
|
|
||||||
"Decline": "Decline",
|
|
||||||
"Delete": "Delete",
|
|
||||||
"Delete cover": "Delete cover",
|
|
||||||
"Delete userpic": "Delete userpic",
|
|
||||||
"delimiter": "delimiter",
|
|
||||||
"Description": "Description",
|
|
||||||
"Discours": "Discours",
|
|
||||||
"Discours is an intellectual environment, a web space and tools that allows authors to collaborate with readers and come together to co-create publications and media projects": "Discours is an intellectual environment, a web space and tools that allows authors to collaborate with readers and come together to co-create publications and media projects.<br/><em>We are convinced that one voice is good, but many is better. We create the most amazing stories together</em>",
|
|
||||||
"Discours is created with our common effort": "Discours exists because of our common effort",
|
|
||||||
"Discours Manifest": "Discours Manifest",
|
|
||||||
"Discours Partners": "Discours Partners",
|
|
||||||
"Discours – an open magazine about culture, science and society": "Discours – an open magazine about culture, science and society",
|
|
||||||
"Discussing": "Discussing",
|
|
||||||
"discussion": "Discours",
|
|
||||||
"Discussion rules": "Discussion rules",
|
|
||||||
"Discussions": "Discussions",
|
|
||||||
"Do you really want to reset all changes?": "Do you really want to reset all changes?",
|
|
||||||
"Dogma": "Dogma",
|
|
||||||
"dogma keywords": "Discours.io, dogma, editorial principles, code of ethics, journalism, community",
|
|
||||||
"Draft successfully deleted": "Draft successfully deleted",
|
|
||||||
"drafts": "drafts",
|
|
||||||
"Drafts": "Drafts",
|
|
||||||
"Drag the image to this area": "Drag the image to this area",
|
|
||||||
"Each image must be no larger than 5 MB.": "Each image must be no larger than 5 MB.",
|
|
||||||
"earlier": "earlier",
|
|
||||||
"Edit": "Edit",
|
|
||||||
"Edit profile": "Edit profile",
|
|
||||||
"Editing": "Editing",
|
|
||||||
"Editor": "Editor",
|
|
||||||
"Email": "Mail",
|
|
||||||
"email not confirmed": "email not confirmed",
|
|
||||||
"enter": "enter",
|
|
||||||
"Enter": "Enter",
|
|
||||||
"Enter a new password": "Enter a new password",
|
|
||||||
"Enter footnote text": "Enter footnote text",
|
|
||||||
"Enter image description": "Enter image description",
|
|
||||||
"Enter image title": "Enter image title",
|
|
||||||
"Enter text": "Enter text",
|
|
||||||
"Enter the code or click the link from email to confirm": "Enter the code from the email or follow the link in the email to confirm registration",
|
|
||||||
"Enter URL address": "Enter URL address",
|
|
||||||
"Enter your new password": "Enter your new password",
|
|
||||||
"Error": "Error",
|
|
||||||
"Experience": "Experience",
|
|
||||||
"Failed to delete comment": "Failed to delete comment",
|
|
||||||
"FAQ": "Tips and suggestions",
|
|
||||||
"Favorite": "Favorites",
|
|
||||||
"Favorite topics": "Favorite topics",
|
|
||||||
"feed": "feed",
|
|
||||||
"Feed": "Feed",
|
|
||||||
"Feed settings": "Feed settings",
|
|
||||||
"Feedback": "Feedback",
|
|
||||||
"Fill email": "Fill email",
|
|
||||||
"Fixed": "Fixed",
|
|
||||||
"Follow": "Follow",
|
|
||||||
"Follow the topic": "Follow the topic",
|
|
||||||
"follower": "follower",
|
|
||||||
"Followers": "Followers",
|
|
||||||
"Following": "Following",
|
|
||||||
"Forgot password?": "Forgot password?",
|
|
||||||
"Forward": "Forward",
|
|
||||||
"from": "from",
|
|
||||||
"Full name": "First and last name",
|
|
||||||
"Gallery": "Gallery",
|
|
||||||
"Gallery name": "Gallery name",
|
|
||||||
"Get to know the most intelligent people of our time, edit and discuss the articles, share your expertise, rate and decide what to publish in the magazine": "Get to know the most intelligent people of our time, edit and discuss the articles, share your expertise, rate and decide what to publish in the magazine",
|
|
||||||
"Go to main page": "Go to main page",
|
|
||||||
"Group Chat": "Group Chat",
|
|
||||||
"Groups": "Groups",
|
|
||||||
"header 1": "header 1",
|
|
||||||
"Header 1": "Header 1",
|
|
||||||
"header 2": "header 2",
|
|
||||||
"Header 2": "Header 2",
|
|
||||||
"header 3": "header 3",
|
|
||||||
"Header 3": "Header 3",
|
|
||||||
"Headers": "Headers",
|
|
||||||
"Help": "Помощь",
|
|
||||||
"Help to edit": "Help to edit",
|
|
||||||
"Here you can customize your profile the way you want.": "Here you can customize your profile the way you want.",
|
|
||||||
"Here you can manage all your Discours subscriptions": "Here you can manage all your Discours subscriptions",
|
|
||||||
"Here you can upload your photo": "Here you can upload your photo",
|
|
||||||
"Hide table of contents": "Hide table of contents",
|
|
||||||
"Highlight": "Highlight",
|
|
||||||
"Hooray! Welcome!": "Hooray! Welcome!",
|
|
||||||
"Horizontal collaborative journalistic platform": "Horizontal collaborative journalism platform",
|
|
||||||
"Hot topics": "Hot topics",
|
|
||||||
"Hotkeys": "Горячие клавиши",
|
|
||||||
"How can I help/skills": "How can I help/skills",
|
|
||||||
"How Discours works": "How Discours works",
|
|
||||||
"How it works": "How it works",
|
|
||||||
"How to help": "How to help?",
|
|
||||||
"How to write a good article": "Как написать хорошую статью",
|
|
||||||
"How to write an article": "How to write an article",
|
|
||||||
"Hundreds of people from different countries and cities share their knowledge and art on the Discours. Join us!": "Hundreds of people from different countries and cities share their knowledge and art on the Discours. Join us!",
|
|
||||||
"I have an account": "I have an account!",
|
|
||||||
"I have no account yet": "I don't have an account yet",
|
|
||||||
"I know the password": "I know the password",
|
|
||||||
"Image format not supported": "Image format not supported",
|
|
||||||
"images": "images",
|
|
||||||
"In bookmarks, you can save favorite discussions and materials that you want to return to": "In bookmarks, you can save favorite discussions and materials that you want to return to",
|
|
||||||
"Inbox": "Inbox",
|
|
||||||
"Incorrect new password confirm": "Incorrect new password confirm",
|
|
||||||
"Incorrect old password": "Incorrect old password",
|
|
||||||
"Incut": "Incut",
|
|
||||||
"Independant magazine with an open horizontal cooperation about culture, science and society": "Independant magazine with an open horizontal cooperation about culture, science and society",
|
|
||||||
"Independent media project about culture, science, art and society with horizontal editing": "Independent media project about culture, science, art and society with horizontal editing",
|
|
||||||
"Insert footnote": "Insert footnote",
|
|
||||||
"Insert video link": "Insert video link",
|
|
||||||
"Interview": "Interview",
|
|
||||||
"Introduce": "Introduction",
|
|
||||||
"Invalid email": "Check if your email is correct",
|
|
||||||
"Invalid image URL": "Invalid image URL",
|
|
||||||
"invalid password": "invalid password",
|
|
||||||
"Invalid url format": "Invalid url format",
|
|
||||||
"Invite": "Invite",
|
|
||||||
"Invite co-authors": "Invite co-authors",
|
|
||||||
"Invite collaborators": "Invite collaborators",
|
|
||||||
"Invite to collab": "Invite to Collab",
|
|
||||||
"It does not look like url": "It doesn't look like a link",
|
|
||||||
"It's OK. Just enter your email to receive a link to change your password": "It's OK. Just enter your email to receive a link to change your password",
|
|
||||||
"italic": "italic",
|
|
||||||
"Italic": "Italic",
|
|
||||||
"Join": "Join",
|
|
||||||
"Join our maillist": "To receive the best postings, just enter your email",
|
|
||||||
"Join the community": "Join the community",
|
|
||||||
"Join the global community of authors!": "Join the global community of authors from all over the world!",
|
|
||||||
"journal": "journal",
|
|
||||||
"jpg, .png, max. 10 mb.": "jpg, .png, макс. 10 мб.",
|
|
||||||
"Just start typing...": "Just start typing...",
|
|
||||||
"keywords": "Discours.io, Discours magazine, Discours, culture, science, art, society, independent journalism, literature, music, cinema, video, photography",
|
|
||||||
"Knowledge base": "Knowledge base",
|
|
||||||
"Language": "Language",
|
|
||||||
"Last rev.": "Посл. изм.",
|
|
||||||
"Let's log in": "Let's log in",
|
|
||||||
"Link copied": "Link copied",
|
|
||||||
"Link copied to clipboard": "Link copied to clipboard",
|
|
||||||
"Link sent, check your email": "Link sent, check your email",
|
|
||||||
"List of authors of the open editorial community": "List of authors of the open editorial community",
|
|
||||||
"Lists": "Lists",
|
|
||||||
"literature": "literature",
|
|
||||||
"Literature": "Literature",
|
|
||||||
"Load more": "Show more",
|
|
||||||
"Loading": "Loading",
|
|
||||||
"Login and security": "Login and security",
|
|
||||||
"Logout": "Logout",
|
|
||||||
"Looks like you forgot to upload the video": "Looks like you forgot to upload the video",
|
|
||||||
"Manifest of samizdat: principles and mission of an open magazine with a horizontal editorial board": "Manifest of samizdat: principles and mission of an open magazine with a horizontal editorial board",
|
|
||||||
"Manifesto": "Manifesto",
|
|
||||||
"Many files, choose only one": "Many files, choose only one",
|
|
||||||
"Mark as read": "Mark as read",
|
|
||||||
"marker list": "marker list",
|
|
||||||
"Material card": "Material card",
|
|
||||||
"Message": "Message",
|
|
||||||
"Message text": "Message text",
|
|
||||||
"min. 1400×1400 pix": "мин. 1400×1400 пикс.",
|
|
||||||
"More": "More",
|
|
||||||
"Most commented": "Commented",
|
|
||||||
"Most read": "Readable",
|
|
||||||
"Move down": "Move down",
|
|
||||||
"Move up": "Move up",
|
|
||||||
"music": "music",
|
|
||||||
"Music": "Music",
|
|
||||||
"my feed": "my ribbon",
|
|
||||||
"My feed": "My feed",
|
|
||||||
"My subscriptions": "Subscriptions",
|
|
||||||
"Name": "Name",
|
|
||||||
"New literary work": "New literary work",
|
|
||||||
"New only": "New only",
|
|
||||||
"New password": "New password",
|
|
||||||
"New stories every day and even more!": "New stories and more are waiting for you every day!",
|
|
||||||
"Newsletter": "Newsletter",
|
|
||||||
"Night mode": "Night mode",
|
|
||||||
"No notifications yet": "No notifications yet",
|
|
||||||
"not verified": "not verified",
|
|
||||||
"Nothing here yet": "There's nothing here yet",
|
|
||||||
"Nothing is here": "There is nothing here",
|
|
||||||
"Notifications": "Notifications",
|
|
||||||
"number list": "number list",
|
|
||||||
"Or paste a link to an image": "Or paste a link to an image",
|
|
||||||
"or sign in with social networks": "or sign in with social networks",
|
|
||||||
"Ordered list": "Ordered list",
|
|
||||||
"Our regular contributor": "Our regular contributor",
|
|
||||||
"Paragraphs": "Абзацев",
|
|
||||||
"Participate in the Discours: share information, join the editorial team": "Участвуйте в Дискурсе: делитесь информацией, присоединяйтесь к редакции",
|
|
||||||
"Participating": "Participating",
|
|
||||||
"Participation": "Participation",
|
|
||||||
"Partners": "Partners",
|
|
||||||
"Password": "Password",
|
|
||||||
"Password again": "Password again",
|
|
||||||
"Password should be at least 8 characters": "Password should be at least 8 characters",
|
|
||||||
"Password should contain at least one number": "Password should contain at least one number",
|
|
||||||
"Password should contain at least one special character: !@#$%^&*": "Password should contain at least one special character: !@#$%^&*",
|
|
||||||
"Password updated!": "Password updated!",
|
|
||||||
"Passwords are not equal": "Passwords are not equal",
|
|
||||||
"Paste Embed code": "Paste Embed code",
|
|
||||||
"Personal": "Personal",
|
|
||||||
"personal data usage and email notifications": "to process personal data and receive email notifications",
|
|
||||||
"Pin": "Pin",
|
|
||||||
"Platform Guide": "Platform Guide",
|
|
||||||
"Please check your email address": "Please check your email address",
|
|
||||||
"Please confirm your email to finish": "Confirm your email and the action will complete",
|
|
||||||
"Please enter a name to sign your comments and publication": "Please enter a name to sign your comments and publication",
|
|
||||||
"Please enter email": "Please enter your email",
|
|
||||||
"Please enter password": "Please enter a password",
|
|
||||||
"Please enter password again": "Please enter password again",
|
|
||||||
"Please, confirm email": "Please confirm email",
|
|
||||||
"Please, set the article title": "Please, set the article title",
|
|
||||||
"Please, set the main topic first": "Please, set the main topic first",
|
|
||||||
"Podcasts": "Podcasts",
|
|
||||||
"Poetry": "Poetry",
|
|
||||||
"Popular": "Popular",
|
|
||||||
"Popular authors": "Popular authors",
|
|
||||||
"post": "post",
|
|
||||||
"Principles": "Community principles",
|
|
||||||
"principles keywords": "Discours.io, communities, values, editorial rules, polyphony, creation",
|
|
||||||
"Professional principles that the open editorial team follows in its work": "Professional principles that the open editorial team follows in its work",
|
|
||||||
"Profile": "Profile",
|
|
||||||
"Profile settings": "Profile settings",
|
|
||||||
"Publications": "Publications",
|
|
||||||
"Publish Album": "Publish Album",
|
|
||||||
"Publish Settings": "Publish Settings",
|
|
||||||
"Published": "Published",
|
|
||||||
"Punchline": "Punchline",
|
|
||||||
"Quit": "Quit",
|
|
||||||
"Quote": "Quote",
|
|
||||||
"Quotes": "Quotes",
|
|
||||||
"Reason uknown": "Reason unknown",
|
|
||||||
"Recent": "Fresh",
|
|
||||||
"Recommend some new topic": "Recommend some new topic",
|
|
||||||
"register": "register",
|
|
||||||
"registered": "registered",
|
|
||||||
"Registered since {date}": "Registered since {date}",
|
|
||||||
"Remove link": "Remove link",
|
|
||||||
"repeat": "repeat",
|
|
||||||
"Repeat new password": "Repeat new password",
|
|
||||||
"Reply": "Reply",
|
|
||||||
"Report": "Complain",
|
|
||||||
"Report an error": "Report an error",
|
|
||||||
"Reports": "Reports",
|
|
||||||
"Required": "Required",
|
|
||||||
"Resend code": "Send confirmation",
|
|
||||||
"resend confirmation link": "resend confirmation link",
|
|
||||||
"Restore password": "Restore password",
|
|
||||||
"Rules of the journal Discours": "Rules of the journal Discours",
|
|
||||||
"Save draft": "Save draft",
|
|
||||||
"Save settings": "Save settings",
|
|
||||||
"Saving...": "Saving...",
|
|
||||||
"Scroll up": "Scroll up",
|
|
||||||
"Search": "Search",
|
|
||||||
"Search author": "Search author",
|
|
||||||
"Search topic": "Search topic",
|
|
||||||
"Sections": "Sections",
|
|
||||||
"Security": "Security",
|
|
||||||
"Select": "Select",
|
|
||||||
"Self-publishing exists thanks to the help of wonderful people from all over the world. Thank you!": "Samizdat exists thanks to the help of wonderful people from all over the world. Thank you!",
|
|
||||||
"Send": "Send",
|
|
||||||
"Send link again": "Send link again",
|
|
||||||
"Settings": "Settings",
|
|
||||||
"Settings for account, email, password and login methods.": "Settings for account, email, password and login methods.",
|
|
||||||
"Share": "Share",
|
|
||||||
"Share publication": "Share publication",
|
|
||||||
"shout": "post",
|
|
||||||
"Show": "Show",
|
|
||||||
"Show lyrics": "Show lyrics",
|
|
||||||
"Show more": "Show more",
|
|
||||||
"Show table of contents": "Show table of contents",
|
|
||||||
"sign up or sign in": "sign up or sign in",
|
|
||||||
"Site search": "Site search",
|
|
||||||
"Slug": "Slug",
|
|
||||||
"slug is used by another user": "Slug is already taken by another user",
|
|
||||||
"Social networks": "Social networks",
|
|
||||||
"Society": "Society",
|
|
||||||
"some authors": "{count} {count, plural, one {author} other {authors}}",
|
|
||||||
"some comments": "{count, plural, =0 {{count} comments} one {{count} comment} few {{count} comments} other {{count} comments}}",
|
|
||||||
"some followers": "{count} {count, plural, one {follower} other {followers}}",
|
|
||||||
"some followings": "{count, plural, =0 {no subscriptions} one {{count} subscription} other {{count} subscriptions}}",
|
|
||||||
"Some new comments to your publication": "{commentsCount, plural, one {New comment} other {{commentsCount} comments}} to your publication",
|
|
||||||
"Some new replies to your comment": "{commentsCount, plural, one {New reply} other {{commentsCount} replays}} to your publication",
|
|
||||||
"some posts": "{count, plural, =0 {no publications} one {{count} publication} other {{count} publications}}",
|
|
||||||
"some shouts": "{count} {count, plural, one {post} other {posts}}",
|
|
||||||
"some views": "{count} {count, plural, one {view} other {views}}",
|
|
||||||
"Something went wrong, check email and password": "Something went wrong. Check your email and password",
|
|
||||||
"Something went wrong, please try again": "Something went wrong, please try again",
|
|
||||||
"Song lyrics": "Song lyrics...",
|
|
||||||
"Song title": "Song title",
|
|
||||||
"Soon": "Скоро",
|
|
||||||
"Sorry, this address is already taken, please choose another one.": "Sorry, this address is already taken, please choose another one",
|
|
||||||
"Special projects": "Special projects",
|
|
||||||
"Special Projects": "Special Projects",
|
|
||||||
"Specify the source and the name of the author": "Specify the source and the name of the author",
|
|
||||||
"Specify your e-mail and we will reply.": "Specify your e-mail and we will reply.",
|
|
||||||
"Start conversation": "Start a conversation",
|
|
||||||
"Start dialog": "Start dialog",
|
|
||||||
"Subsccriptions": "Subscriptions",
|
|
||||||
"Subscribe": "Subscribe",
|
|
||||||
"Subscribe to the best publications newsletter": "Subscribe to the best publications newsletter",
|
|
||||||
"Subscribe us": "Subscribe us",
|
|
||||||
"Subscribe what you like to tune your personal feed": "Subscribe to topics that interest you to customize your personal feed and get instant updates on new posts and discussions",
|
|
||||||
"Subscribe who you like to tune your personal feed": "Subscribe to authors you're interested in to customize your personal feed and get instant updates on new posts and discussions",
|
|
||||||
"subscriber": "subscriber",
|
|
||||||
"subscriber_rp": "subscriber",
|
|
||||||
"subscribers": "subscribers",
|
|
||||||
"Subscribing...": "Subscribing...",
|
|
||||||
"subscribing...": "subscribing...",
|
|
||||||
"subscription": "subscription",
|
|
||||||
"Subscription": "Subscription",
|
|
||||||
"subscription_rp": "subscription",
|
|
||||||
"subscriptions": "subscriptions",
|
|
||||||
"Subscriptions": "Subscriptions",
|
|
||||||
"Substrate": "Substrate",
|
|
||||||
"Success": "Success",
|
|
||||||
"Successfully authorized": "Authorization successful",
|
|
||||||
"Suggest an idea": "Suggest an idea",
|
|
||||||
"Support Discours": "Support Discours",
|
|
||||||
"Support the project": "Support the project",
|
|
||||||
"Support us": "Support us",
|
|
||||||
"terms of use": "terms of use",
|
|
||||||
"Terms of use": "Site rules",
|
|
||||||
"terms of use keywords": "Discours.io, site rules, terms of use",
|
|
||||||
"Text checking": "Text checking",
|
|
||||||
"Thank you": "Thank you",
|
|
||||||
"Thank you for reaching us": "Thank you for reaching us",
|
|
||||||
"Thank you!": "Thank you!",
|
|
||||||
"The address is already taken": "The address is already taken",
|
|
||||||
"The most interesting publications on the topic": "The most interesting publications on the topic {topicName}",
|
|
||||||
"Thematic table of contents of the magazine. Here you can find all the topics that community authors have written about.": "Thematic table of contents of the magazine. Here you can find all the topics that community authors have written about.",
|
|
||||||
"Thematic table of contents of the magazine. Here you can find all the topics that the community authors wrote about": "Thematic table of contents of the magazine. Here you can find all the topics that the community authors wrote about",
|
|
||||||
"Themes and plots": "Themes and plots",
|
|
||||||
"Theory": "Theory",
|
|
||||||
"There are unsaved changes in your profile settings. Are you sure you want to leave the page without saving?": "There are unsaved changes in your profile settings. Are you sure you want to leave the page without saving?",
|
|
||||||
"There are unsaved changes in your publishing settings. Are you sure you want to leave the page without saving?": "There are unsaved changes in your publishing settings. Are you sure you want to leave the page without saving?",
|
|
||||||
"This comment has not yet been rated": "This comment has not yet been rated",
|
|
||||||
"This content is not published yet": "This content is not published yet",
|
|
||||||
"This email is": "This email is",
|
|
||||||
"This email is not verified": "This email is not verified",
|
|
||||||
"This email is registered": "This email is registered",
|
|
||||||
"This email is verified": "This email is verified",
|
|
||||||
"This functionality is currently not available, we would like to work on this issue. Use the download link.": "This functionality is currently not available, we would like to work on this issue. Use the download link.",
|
|
||||||
"This month": "This month",
|
|
||||||
"This way we ll realize that you re a real person and ll take your vote into account. And you ll see how others voted": "This way we ll realize that you re a real person and ll take your vote into account. And you ll see how others voted",
|
|
||||||
"This way you ll be able to subscribe to authors, interesting topics and customize your feed": "This way you ll be able to subscribe to authors, interesting topics and customize your feed",
|
|
||||||
"This week": "This week",
|
|
||||||
"This year": "This year",
|
|
||||||
"To find publications, art, comments, authors and topics of interest to you, just start typing your query": "To find publications, art, comments, authors and topics of interest to you, just start typing your query",
|
|
||||||
"To leave a comment please": "To leave a comment please",
|
|
||||||
"To write a comment, you must": "To write a comment, you must",
|
|
||||||
"today": "today",
|
|
||||||
"Top authors": "Authors rating",
|
|
||||||
"Top commented": "Most commented",
|
|
||||||
"Top discussed": "Top discussed",
|
|
||||||
"Top month": "Top of the month",
|
|
||||||
"Top rated": "Popular",
|
|
||||||
"Top recent": "Most recent",
|
|
||||||
"Top topics": "Interesting topics",
|
|
||||||
"Top viewed": "Most viewed",
|
|
||||||
"Topic is supported by": "Topic is supported by",
|
|
||||||
"topicKeywords": "{topic}, Discours.io, articles, journalism, research",
|
|
||||||
"topics": "topics",
|
|
||||||
"Topics": "Topics",
|
|
||||||
"Topics which supported by author": "Topics which supported by author",
|
|
||||||
"try": "попробуйте",
|
|
||||||
"Try to find another way": "Try to find another way",
|
|
||||||
"Unfollow": "Unfollow",
|
|
||||||
"Unfollow the topic": "Unfollow the topic",
|
|
||||||
"Unnamed draft": "Unnamed draft",
|
|
||||||
"Unsubscribing...": "Unsubscribing...",
|
|
||||||
"Upload": "Upload",
|
|
||||||
"Upload error": "Upload error",
|
|
||||||
"Upload userpic": "Upload userpic",
|
|
||||||
"Upload video": "Upload video",
|
|
||||||
"Uploading image": "Uploading image",
|
|
||||||
"user already exist": "user already exists",
|
|
||||||
"User was not found": "User was not found",
|
|
||||||
"Username": "Username",
|
|
||||||
"Userpic": "Userpic",
|
|
||||||
"Users": "Users",
|
|
||||||
"verified": "verified",
|
|
||||||
"video": "video",
|
|
||||||
"Video": "Video",
|
|
||||||
"Video format not supported": "Video format not supported",
|
|
||||||
"view": "view",
|
|
||||||
"Views": "Views",
|
|
||||||
"Volounteering": "Volounteering",
|
|
||||||
"Want to suggest, discuss or advise something? Share a topic or an idea? Please send us a message!": "Want to suggest, discuss or advise something? Share a topic or an idea? Please send us a message!",
|
|
||||||
"We are working on collaborative editing of articles and in the near future you will have an amazing opportunity - to create together with your colleagues": "We are working on collaborative editing of articles and in the near future you will have an amazing opportunity - to create together with your colleagues",
|
|
||||||
"We can't find you, check email or": "We can't find you, check email or",
|
|
||||||
"We couldn't find anything for your request": "We couldn’t find anything for your request",
|
|
||||||
"We know you, please try to login": "This email address is already registered, please try to login",
|
|
||||||
"We've sent you a message with a link to enter our website.": "We've sent you an email with a link to your email. Follow the link in the email to enter our website.",
|
|
||||||
"Welcome to Discours": "Welcome to Discours",
|
|
||||||
"Welcome to Discours to add to your bookmarks": "Welcome to Discours to add to your bookmarks",
|
|
||||||
"Welcome to Discours to participate in discussions": "Welcome to Discours to participate in discussions",
|
|
||||||
"Welcome to Discours to publish articles": "Welcome to Discours to publish articles",
|
|
||||||
"Welcome to Discours to subscribe": "Welcome to Discours to subscribe",
|
|
||||||
"Welcome to Discours to subscribe to new publications": "Welcome to Discours to subscribe to new publications",
|
|
||||||
"Welcome to Discours to vote": "Welcome to Discours to vote",
|
|
||||||
"Where": "From",
|
|
||||||
"Why you can earn a hole in your karma and how to receive rays of gratitude for your contribution to discussions in samizdat communities": "Why you can earn a hole in your karma and how to receive rays of gratitude for your contribution to discussions in samizdat communities",
|
|
||||||
"Words": "Слов",
|
|
||||||
"Work with us": "Cooperate with Discours",
|
|
||||||
"Write a comment...": "Write a comment...",
|
|
||||||
"Write a short introduction": "Write a short introduction",
|
|
||||||
"Write about the topic": "Write about the topic",
|
|
||||||
"Write an article": "Write an article",
|
|
||||||
"Write comment": "Write comment",
|
|
||||||
"Write good articles, comment\nand it won't be so empty here": "Write good articles, comment\nand it won't be so empty here",
|
|
||||||
"Write message": "Write a message",
|
|
||||||
"Write to us": "Write to us",
|
|
||||||
"Write your colleagues name or email": "Write your colleague's name or email",
|
|
||||||
"yesterday": "yesterday",
|
|
||||||
"You can": "You can",
|
|
||||||
"You can download multiple tracks at once in .mp3, .wav or .flac formats": "You can download multiple tracks at once in .mp3, .wav or .flac formats",
|
|
||||||
"You can now login using your new password": "Теперь вы можете входить с помощью нового пароля",
|
|
||||||
"You can't edit this post": "You can't edit this post",
|
|
||||||
"You were successfully authorized": "You were successfully authorized",
|
|
||||||
"You ll be able to participate in discussions, rate others' comments and learn about new responses": "You ll be able to participate in discussions, rate others' comments and learn about new responses",
|
|
||||||
"You've confirmed email": "You've confirmed email",
|
|
||||||
"You've reached a non-existed page": "You've reached a non-existed page",
|
|
||||||
"Your contact for answer": "Your contact for answer",
|
|
||||||
"Your email": "Your email",
|
|
||||||
"Your name will appear on your profile page and as your signature in publications, comments and responses.": "Your name will appear on your profile page and as your signature in publications, comments and responses"
|
|
||||||
}
|
|
|
@ -1,579 +0,0 @@
|
||||||
{
|
|
||||||
"A guide to horizontal editorial: how an open journal works": "Гид по горизонтальной редакции: как работает открытый журнал",
|
|
||||||
"A short introduction to keep the reader interested": "Добавьте вступление, чтобы заинтересовать читателя",
|
|
||||||
"About": "О себе",
|
|
||||||
"About the project": "О проекте",
|
|
||||||
"actions": "действия",
|
|
||||||
"Add": "Добавить",
|
|
||||||
"Add a few topics so that the reader knows what your content is about and can find it on pages of topics that interest them. Topics can be swapped, the first topic becomes the title": "Добавьте несколько тем, чтобы читатель знал, о чем ваш материал, и мог найти его на страницах интересных ему тем. Темы можно менять местами, первая тема становится заглавной",
|
|
||||||
"Add a link or click plus to embed media": "Добавьте ссылку или нажмите плюс для вставки медиа",
|
|
||||||
"Add an embed widget": "Добавить embed-виджет",
|
|
||||||
"Add another image": "Добавить другое изображение",
|
|
||||||
"Add audio": "Добавить аудио",
|
|
||||||
"Add blockquote": "Добавить цитату",
|
|
||||||
"Add comment": "Комментировать",
|
|
||||||
"Add cover": "Добавить обложку",
|
|
||||||
"Add image": "Добавить изображение",
|
|
||||||
"Add images": "Добавить изображения",
|
|
||||||
"Add intro": "Добавить вступление",
|
|
||||||
"Add link": "Добавить ссылку",
|
|
||||||
"add link": "добавить ссылку",
|
|
||||||
"Add rule": "Добавить разделитель",
|
|
||||||
"Add signature": "Добавить подпись",
|
|
||||||
"Add subtitle": "Добавить подзаголовок",
|
|
||||||
"Add to bookmarks": "Добавить в закладки",
|
|
||||||
"Add url": "Добавить ссылку",
|
|
||||||
"Address on Discours": "Адрес на Дискурсе",
|
|
||||||
"Album name": "Название альбома",
|
|
||||||
"Alignment center": "По центру",
|
|
||||||
"Alignment left": "По левому краю",
|
|
||||||
"Alignment right": "По правому краю",
|
|
||||||
"All": "Все",
|
|
||||||
"All articles": "Все материалы",
|
|
||||||
"All authors": "Все авторы",
|
|
||||||
"All posts": "Все публикации",
|
|
||||||
"All posts rating": "Рейтинг всех постов",
|
|
||||||
"All topics": "Все темы",
|
|
||||||
"all topics": "все темы",
|
|
||||||
"Almost done! Check your email.": "Почти готово! Осталось подтвердить вашу почту.",
|
|
||||||
"and some more authors": "{restUsersCount, plural, =0 {} one { и ещё 1 пользователя} few { и ещё {restUsersCount} пользователей} other { и ещё {restUsersCount} пользователей}}",
|
|
||||||
"Anything else": "Что-либо ещё",
|
|
||||||
"Are you sure you want to delete this comment?": "Уверены, что хотите удалить этот комментарий?",
|
|
||||||
"Are you sure you want to delete this draft?": "Уверены, что хотите удалить этот черновик?",
|
|
||||||
"Are you sure you want to to proceed the action?": "Вы уверены, что хотите продолжить?",
|
|
||||||
"Art": "Искусство",
|
|
||||||
"article": "статья",
|
|
||||||
"Artist": "Исполнитель",
|
|
||||||
"Artist...": "Исполнитель...",
|
|
||||||
"Artworks": "Артворки",
|
|
||||||
"Audio": "Аудио",
|
|
||||||
"Author": "Автор",
|
|
||||||
"author": "автор",
|
|
||||||
"Authors": "Авторы",
|
|
||||||
"authors": "авторы",
|
|
||||||
"Autotypograph": "Автотипограф",
|
|
||||||
"Back": "Назад",
|
|
||||||
"Back to editor": "Вернуться в редактор",
|
|
||||||
"Back to main page": "Вернуться на главную",
|
|
||||||
"back to menu": "назад в меню",
|
|
||||||
"Be the first to rate": "Оцените первым",
|
|
||||||
"Become an author": "Стать автором",
|
|
||||||
"Bold": "Жирный",
|
|
||||||
"bold": "жирный",
|
|
||||||
"Bookmarked": "Сохранено",
|
|
||||||
"Bookmarks": "Закладки",
|
|
||||||
"bookmarks": "закладки",
|
|
||||||
"Bullet list": "Маркированный список",
|
|
||||||
"By alphabet": "По алфавиту",
|
|
||||||
"By authors": "По авторам",
|
|
||||||
"By name": "По имени",
|
|
||||||
"By popularity": "По популярности",
|
|
||||||
"By rating": "По рейтингу",
|
|
||||||
"By relevance": "По релевантности",
|
|
||||||
"By shouts": "По публикациям",
|
|
||||||
"By signing up you agree with our": "Регистрируясь, вы соглашаетесь с",
|
|
||||||
"By time": "По порядку",
|
|
||||||
"By title": "По названию",
|
|
||||||
"By updates": "По обновлениям",
|
|
||||||
"By views": "По просмотрам",
|
|
||||||
"Can make any changes, accept or reject suggestions, and share access with others": "Может вносить любые изменения, принимать и отклонять предложения, а также делиться доступом с другими",
|
|
||||||
"Can offer edits and comments, but cannot edit the post or share access with others": "Может предлагать правки и комментарии, но не может изменять пост и делиться доступом с другими",
|
|
||||||
"Can write and edit text directly, and accept or reject suggestions from others": "Может писать и редактировать текст напрямую, а также принимать или отклонять предложения других",
|
|
||||||
"Cancel": "Отмена",
|
|
||||||
"cancel": "отменить",
|
|
||||||
"Cancel changes": "Отменить изменения",
|
|
||||||
"Change password": "Сменить пароль",
|
|
||||||
"Characters": "Знаков",
|
|
||||||
"Chat Title": "Тема дискурса",
|
|
||||||
"Choose a post type": "Выберите тип публикации",
|
|
||||||
"Choose a title image for the article. You can immediately see how the publication card will look like.": "Выберите заглавное изображение для статьи. Тут же сразу можно увидеть как будет выглядеть карточка публикации.",
|
|
||||||
"Choose who you want to write to": "Выберите кому хотите написать",
|
|
||||||
"Close": "Закрыть",
|
|
||||||
"Co-author": "Соавтор",
|
|
||||||
"Collaborate": "Помочь редактировать",
|
|
||||||
"Collaborators": "Соавторы",
|
|
||||||
"Collections": "Коллекции",
|
|
||||||
"collections": "коллекции",
|
|
||||||
"Come up with a subtitle for your story": "Придумайте подзаголовок вашей истории",
|
|
||||||
"Come up with a title for your story": "Придумайте заголовок вашей истории",
|
|
||||||
"Coming soon": "Уже скоро",
|
|
||||||
"Comment": "Комментировать",
|
|
||||||
"Comment successfully deleted": "Комментарий успешно удален",
|
|
||||||
"Commentator": "Комментатор",
|
|
||||||
"Commenting": "Комментирование",
|
|
||||||
"Comments": "Комментарии",
|
|
||||||
"Common feed": "Общая лента",
|
|
||||||
"Communities": "Сообщества",
|
|
||||||
"community": "сообщество",
|
|
||||||
"Community Discussion Rules": "Правила дискуссий в сообществе",
|
|
||||||
"Community Principles": "Принципы сообщества",
|
|
||||||
"Community values and rules of engagement for the open editorial team": "Ценности сообщества и правила взаимодействия открытой редакции",
|
|
||||||
"Confirm": "Подтвердить",
|
|
||||||
"Confirm your new password": "Подтвердите новый пароль",
|
|
||||||
"Connect": "Привязать",
|
|
||||||
"Contents": "Оглавление",
|
|
||||||
"Contribute to free samizdat. Support Discours - an independent non-profit publication that works only for you. Become a pillar of the open newsroom": "Внесите вклад в свободный самиздат. Поддержите Дискурс — независимое некоммерческое издание, которое работает только для вас. Станьте опорой открытой редакции",
|
|
||||||
"Cooperate": "Соучаствовать",
|
|
||||||
"Copy": "Скопировать",
|
|
||||||
"Copy link": "Скопировать ссылку",
|
|
||||||
"Corrections history": "История правок",
|
|
||||||
"Create account": "Создать аккаунт",
|
|
||||||
"Create an account to add to your bookmarks": "Создайте аккаунт, чтобы добавить в закладки",
|
|
||||||
"Create an account to participate in discussions": "Создайте аккаунт для участия в дискуссиях",
|
|
||||||
"Create an account to publish articles": "Создайте аккаунт, чтобы публиковать статьи",
|
|
||||||
"Create an account to subscribe": "Создайте аккаунт, чтобы подписаться",
|
|
||||||
"Create an account to subscribe to new publications": "Создайте аккаунт для подписки на новые публикации",
|
|
||||||
"Create an account to vote": "Создайте аккаунт, чтобы голосовать",
|
|
||||||
"Create Chat": "Создать чат",
|
|
||||||
"Create gallery": "Создать галерею",
|
|
||||||
"Create Group": "Создать группу",
|
|
||||||
"Create post": "Создать публикацию",
|
|
||||||
"Create video": "Создать видео",
|
|
||||||
"create_chat": "Создать чат",
|
|
||||||
"create_group": "Создать группу",
|
|
||||||
"Crop image": "Кадрировать изображение",
|
|
||||||
"Culture": "Культура",
|
|
||||||
"Current password": "Текущий пароль",
|
|
||||||
"Date of Birth": "Дата рождения",
|
|
||||||
"Decline": "Отмена",
|
|
||||||
"Delete": "Удалить",
|
|
||||||
"Delete cover": "Удалить обложку",
|
|
||||||
"Delete userpic": "Удалить аватар",
|
|
||||||
"delimiter": "разделитель",
|
|
||||||
"Description": "Описание",
|
|
||||||
"Discours": "Дискурс",
|
|
||||||
"Discours is an intellectual environment, a web space and tools that allows authors to collaborate with readers and come together to co-create publications and media projects": "Дискурс — это интеллектуальная среда, веб-пространство и инструменты, которые позволяют авторам сотрудничать с читателями и объединяться для совместного создания публикаций и медиапроектов.<br/>Мы убеждены, один голос хорошо, а много — лучше. Самые потрясающиe истории мы создаём вместе.",
|
|
||||||
"Discours is created with our common effort": "Дискурс существует благодаря нашему общему вкладу",
|
|
||||||
"Discours Manifest": "Манифест Дискурса",
|
|
||||||
"Discours Partners": "Партнеры Дискурса",
|
|
||||||
"Discours – an open magazine about culture, science and society": "Дискурс – открытый журнал о культуре, науке и обществе",
|
|
||||||
"Discours_theme": "Тема дискурса",
|
|
||||||
"Discussing": "Обсуждаемое",
|
|
||||||
"discussion": "дискурс",
|
|
||||||
"Discussion rules": "Правила дискуссий",
|
|
||||||
"Discussions": "Дискуссии",
|
|
||||||
"Do you really want to reset all changes?": "Вы действительно хотите сбросить все изменения?",
|
|
||||||
"Dogma": "Догма",
|
|
||||||
"dogma keywords": "Discours.io, догма, редакционные принципы, этический кодекс, журналистика, сообщество",
|
|
||||||
"Draft successfully deleted": "Черновик успешно удален",
|
|
||||||
"Drafts": "Черновики",
|
|
||||||
"drafts": "черновики",
|
|
||||||
"Drag the image to this area": "Перетащите изображение в эту область",
|
|
||||||
"Each image must be no larger than 5 MB.": "Каждое изображение должно быть размером не больше 5 мб.",
|
|
||||||
"earlier": "ранее",
|
|
||||||
"Edit": "Редактировать",
|
|
||||||
"Edit profile": "Редактировать профиль",
|
|
||||||
"Editing": "Редактирование",
|
|
||||||
"Editor": "Редактор",
|
|
||||||
"Email": "Почта",
|
|
||||||
"email not confirmed": "email не подтвержден",
|
|
||||||
"Enter": "Войти",
|
|
||||||
"enter": "войти",
|
|
||||||
"Enter a new password": "Введите новый пароль",
|
|
||||||
"Enter footnote text": "Введите текст сноски",
|
|
||||||
"Enter image description": "Введите описание изображения",
|
|
||||||
"Enter image title": "Введите название изображения",
|
|
||||||
"Enter text": "Введите текст",
|
|
||||||
"Enter the code or click the link from email to confirm": "Введите код из письма или пройдите по ссылке в письме для подтверждения регистрации",
|
|
||||||
"Enter URL address": "Введите адрес ссылки",
|
|
||||||
"Enter your new password": "Введите новый пароль",
|
|
||||||
"Error": "Ошибка",
|
|
||||||
"Experience": "Личный опыт",
|
|
||||||
"Failed to delete comment": "Не удалось удалить комментарий",
|
|
||||||
"FAQ": "Советы и предложения",
|
|
||||||
"Favorite": "Избранное",
|
|
||||||
"Favorite topics": "Избранные темы",
|
|
||||||
"Feed": "Лента",
|
|
||||||
"feed": "лента",
|
|
||||||
"Feed settings": "Настроить ленту",
|
|
||||||
"Feedback": "Обратная связь",
|
|
||||||
"Fill email": "Введите почту",
|
|
||||||
"Fixed": "Все поправлено",
|
|
||||||
"Follow": "Подписаться",
|
|
||||||
"Follow the topic": "Подписаться на тему",
|
|
||||||
"follower": "подписчик",
|
|
||||||
"Followers": "Подписчики",
|
|
||||||
"Following": "Вы подписаны",
|
|
||||||
"Forgot password?": "Забыли пароль?",
|
|
||||||
"Forward": "Переслать",
|
|
||||||
"from": "от",
|
|
||||||
"Full name": "Имя и фамилия",
|
|
||||||
"Gallery": "Галерея",
|
|
||||||
"Gallery name": "Название галереи",
|
|
||||||
"Genre...": "Жанр...",
|
|
||||||
"Get notifications": "Получать уведомления",
|
|
||||||
"Get to know the most intelligent people of our time, edit and discuss the articles, share your expertise, rate and decide what to publish in the magazine": "Познакомитесь с выдающимися людьми нашего времени, участвуйте в редактировании и обсуждении статей, выступайте экспертом, оценивайте материалы других авторов со всего мира и определяйте, какие статьи будут опубликованы в журнале",
|
|
||||||
"Go to main page": "Перейти на главную",
|
|
||||||
"Group Chat": "Общий чат",
|
|
||||||
"Groups": "Группы",
|
|
||||||
"Header": "Заголовок",
|
|
||||||
"Header 1": "Заголовок 1",
|
|
||||||
"header 1": "заголовок 1",
|
|
||||||
"Header 2": "Заголовок 2",
|
|
||||||
"header 2": "заголовок 2",
|
|
||||||
"Header 3": "Заголовок 3",
|
|
||||||
"header 3": "заголовок 3",
|
|
||||||
"Headers": "Заголовки",
|
|
||||||
"Help": "Помощь",
|
|
||||||
"Help to edit": "Помочь редактировать",
|
|
||||||
"Here you can customize your profile the way you want.": "Здесь можно настроить свой профиль так, как вы хотите.",
|
|
||||||
"Here you can manage all your Discours subscriptions": "Здесь можно управлять всеми своими подписками на Дискурсе",
|
|
||||||
"Here you can upload your photo": "Здесь вы можете загрузить свою фотографию",
|
|
||||||
"Hide table of contents": "Скрыть главление",
|
|
||||||
"Highlight": "Подсветка",
|
|
||||||
"Hooray! Welcome!": "Ура! Добро пожаловать!",
|
|
||||||
"Horizontal collaborative journalistic platform": "Открытая платформа<br/>для независимой журналистики",
|
|
||||||
"Hot topics": "Горячие темы",
|
|
||||||
"Hotkeys": "Горячие клавиши",
|
|
||||||
"How can I help/skills": "Чем могу помочь/навыки",
|
|
||||||
"How Discours works": "Как устроен Дискурс",
|
|
||||||
"How it works": "Как это работает",
|
|
||||||
"How to help": "Как помочь?",
|
|
||||||
"How to write a good article": "Как написать хорошую статью",
|
|
||||||
"How to write an article": "Как написать статью",
|
|
||||||
"Hundreds of people from different countries and cities share their knowledge and art on the Discours. Join us!": "Сотни людей из разных стран и городов делятся своими знаниями и искусством на Дискурсе. Присоединяйтесь!",
|
|
||||||
"I have an account": "У меня есть аккаунт!",
|
|
||||||
"I have no account yet": "У меня еще нет аккаунта",
|
|
||||||
"I know the password": "Я знаю пароль!",
|
|
||||||
"Image format not supported": "Тип изображения не поддерживается",
|
|
||||||
"images": "изображения",
|
|
||||||
"In bookmarks, you can save favorite discussions and materials that you want to return to": "В закладках можно сохранять избранные дискуссии и материалы, к которым хочется вернуться",
|
|
||||||
"Inbox": "Входящие",
|
|
||||||
"Incorrect new password confirm": "Неверное подтверждение нового пароля",
|
|
||||||
"Incorrect old password": "Старый пароль не верен",
|
|
||||||
"Incut": "Подверстка",
|
|
||||||
"Independant magazine with an open horizontal cooperation about culture, science and society": "Независимый журнал с открытой горизонтальной редакцией о культуре, науке и обществе",
|
|
||||||
"Independent media project about culture, science, art and society with horizontal editing": "Независимый медиапроект о культуре, науке, искусстве и обществе с горизонтальной редакцией",
|
|
||||||
"Insert footnote": "Вставить сноску",
|
|
||||||
"Insert video link": "Вставить ссылку на видео",
|
|
||||||
"Interview": "Интервью",
|
|
||||||
"Introduce": "Представление",
|
|
||||||
"Invalid email": "Проверьте правильность ввода почты",
|
|
||||||
"Invalid image URL": "Некорректная ссылка на изображение",
|
|
||||||
"invalid password": "некорректный пароль",
|
|
||||||
"Invalid url format": "Неверный формат ссылки",
|
|
||||||
"Invite": "Пригласить",
|
|
||||||
"Invite co-authors": "Пригласить соавторов",
|
|
||||||
"Invite collaborators": "Пригласить соавторов",
|
|
||||||
"Invite experts": "Пригласить экспертов",
|
|
||||||
"Invite to collab": "Пригласить к участию",
|
|
||||||
"It does not look like url": "Это не похоже на ссылку",
|
|
||||||
"It's OK. Just enter your email to receive a link to change your password": "Ничего страшного. Просто укажите свою почту, чтобы получить ссылку для смены пароля",
|
|
||||||
"Italic": "Курсив",
|
|
||||||
"italic": "курсив",
|
|
||||||
"Join": "Присоединиться",
|
|
||||||
"Join our maillist": "Чтобы получать рассылку лучших публикаций, просто укажите свою почту",
|
|
||||||
"Join the community": "Присоединиться к сообществу",
|
|
||||||
"Join the global community of authors!": "Присоединятесь к глобальному сообществу авторов со всего мира!",
|
|
||||||
"journal": "журнал",
|
|
||||||
"jpg, .png, max. 10 mb.": "jpg, .png, макс. 10 мб.",
|
|
||||||
"Just start typing...": "Просто начните печатать...",
|
|
||||||
"Karma": "Карма",
|
|
||||||
"keywords": "Discours.io, журнал Дискурс, Дискурс, культура, наука, искусство, общество, независимая журналистика, литература, музыка, кино, видео, фотографии",
|
|
||||||
"Knowledge base": "База знаний",
|
|
||||||
"Language": "Язык",
|
|
||||||
"Last rev.": "Посл. изм.",
|
|
||||||
"Let's log in": "Давайте авторизуемся",
|
|
||||||
"Link copied": "Ссылка скопирована",
|
|
||||||
"Link copied to clipboard": "Ссылка скопирована в буфер обмена",
|
|
||||||
"Link sent, check your email": "Ссылка отправлена, проверьте почту",
|
|
||||||
"List of authors of the open editorial community": "Список авторов сообщества открытой редакции",
|
|
||||||
"Lists": "Списки",
|
|
||||||
"Literature": "Литература",
|
|
||||||
"literature": "литература",
|
|
||||||
"Load more": "Показать ещё",
|
|
||||||
"Loading": "Загрузка",
|
|
||||||
"Login and security": "Вход и безопасность",
|
|
||||||
"Logout": "Выход",
|
|
||||||
"Looks like you forgot to upload the video": "Похоже, что вы забыли загрузить видео",
|
|
||||||
"Manifest of samizdat: principles and mission of an open magazine with a horizontal editorial board": "Манифест самиздата: принципы и миссия открытого журнала с горизонтальной редакцией",
|
|
||||||
"Manifesto": "Манифест",
|
|
||||||
"Many files, choose only one": "Много файлов, выберете один",
|
|
||||||
"Mark as read": "Отметить прочитанным",
|
|
||||||
"marker list": "маркир. список",
|
|
||||||
"Material card": "Карточка материала",
|
|
||||||
"Message": "Написать",
|
|
||||||
"Message text": "Текст сообщения",
|
|
||||||
"min. 1400×1400 pix": "мин. 1400×1400 пикс.",
|
|
||||||
"More": "Ещё",
|
|
||||||
"Most commented": "Комментируемое",
|
|
||||||
"Most read": "Читаемое",
|
|
||||||
"Move down": "Переместить вниз",
|
|
||||||
"Move up": "Переместить вверх",
|
|
||||||
"Music": "Музыка",
|
|
||||||
"music": "музыка",
|
|
||||||
"My feed": "Моя лента",
|
|
||||||
"my feed": "моя лента",
|
|
||||||
"My subscriptions": "Подписки",
|
|
||||||
"Name": "Имя",
|
|
||||||
"New literary work": "Новое произведение",
|
|
||||||
"New only": "Только новые",
|
|
||||||
"New password": "Новый пароль",
|
|
||||||
"New stories every day and even more!": "Каждый день вас ждут новые истории и ещё много всего интересного!",
|
|
||||||
"Newsletter": "Рассылка",
|
|
||||||
"Night mode": "Ночная тема",
|
|
||||||
"No notifications yet": "Уведомлений пока нет",
|
|
||||||
"No such account, please try to register": "Такой адрес не найден, попробуйте зарегистрироваться",
|
|
||||||
"not verified": "ещё не подтверждён",
|
|
||||||
"Nothing here yet": "Здесь пока ничего нет",
|
|
||||||
"Nothing is here": "Здесь ничего нет",
|
|
||||||
"Notifications": "Уведомления",
|
|
||||||
"number list": "нумер. список",
|
|
||||||
"or": "или",
|
|
||||||
"Or paste a link to an image": "Или вставьте ссылку на изображение",
|
|
||||||
"or sign in with social networks": "или войдите через соцсеть",
|
|
||||||
"Ordered list": "Нумерованный список",
|
|
||||||
"Our regular contributor": "Наш постоянный автор",
|
|
||||||
"Paragraphs": "Абзацев",
|
|
||||||
"Participate in the Discours: share information, join the editorial team": "Participate in the Discours: share information, join the editorial team",
|
|
||||||
"Participating": "Участвовать",
|
|
||||||
"Participation": "Соучастие",
|
|
||||||
"Partners": "Партнёры",
|
|
||||||
"Password": "Пароль",
|
|
||||||
"Password again": "Пароль ещё раз",
|
|
||||||
"Password should be at least 8 characters": "Пароль должен быть не менее 8 символов",
|
|
||||||
"Password should contain at least one number": "Пароль должен содержать хотя бы одну цифру",
|
|
||||||
"Password should contain at least one special character: !@#$%^&*": "Пароль должен содержать хотя бы один спецсимвол: !@#$%^&*",
|
|
||||||
"Password updated!": "Пароль обновлен!",
|
|
||||||
"Passwords are not equal": "Пароли не совпадают",
|
|
||||||
"Paste Embed code": "Вставьте embed код",
|
|
||||||
"Personal": "Личные",
|
|
||||||
"personal data usage and email notifications": "на обработку персональных данных и на получение почтовых уведомлений",
|
|
||||||
"Pin": "Закрепить",
|
|
||||||
"Platform Guide": "Гид по дискурсу",
|
|
||||||
"Please check your email address": "Пожалуйста, проверьте введенный адрес почты",
|
|
||||||
"Please check your inbox! We have sent a password reset link.": "Пожалуйста, проверьте свою почту, мы отправили вам письмо со ссылкой для сброса пароля",
|
|
||||||
"Please confirm your email to finish": "Подтвердите почту и действие совершится",
|
|
||||||
"Please enter a name to sign your comments and publication": "Пожалуйста, введите имя, которое будет отображаться на сайте",
|
|
||||||
"Please enter email": "Пожалуйста, введите почту",
|
|
||||||
"Please enter password": "Пожалуйста, введите пароль",
|
|
||||||
"Please enter password again": "Пожалуйста, введите пароль ещё рез",
|
|
||||||
"Please, confirm email": "Пожалуйста, подтвердите электронную почту",
|
|
||||||
"Please, set the article title": "Пожалуйста, задайте заголовок статьи",
|
|
||||||
"Please, set the main topic first": "Пожалуйста, сначала выберите главную тему",
|
|
||||||
"Podcasts": "Подкасты",
|
|
||||||
"Poetry": "Поэзия",
|
|
||||||
"Popular": "Популярное",
|
|
||||||
"Popular authors": "Популярные авторы",
|
|
||||||
"post": "пост",
|
|
||||||
"Preview": "Предпросмотр",
|
|
||||||
"Principles": "Принципы сообщества",
|
|
||||||
"principles keywords": "Discours.io, сообщества, ценности, правила редакции, многоголосие, созидание",
|
|
||||||
"Professional principles that the open editorial team follows in its work": "Профессиональные принципы, которым открытая редакция следует в работе",
|
|
||||||
"Profile": "Профиль",
|
|
||||||
"Profile settings": "Настройки профиля",
|
|
||||||
"Profile successfully saved": "Профиль успешно сохранён",
|
|
||||||
"Publication settings": "Настройки публикации",
|
|
||||||
"Publications": "Публикации",
|
|
||||||
"Publish": "Опубликовать",
|
|
||||||
"Publish Album": "Опубликовать альбом",
|
|
||||||
"Publish Settings": "Настройки публикации",
|
|
||||||
"Published": "Опубликованные",
|
|
||||||
"Punchline": "Панчлайн",
|
|
||||||
"Quit": "Выйти",
|
|
||||||
"Quote": "Цитата",
|
|
||||||
"Quotes": "Цитаты",
|
|
||||||
"Reason uknown": "Причина неизвестна",
|
|
||||||
"Recent": "Свежее",
|
|
||||||
"Recommend some new topic": "Предложить тему",
|
|
||||||
"register": "зарегистрируйтесь",
|
|
||||||
"registered": "уже зарегистрирован",
|
|
||||||
"Registered since {date}": "На сайте c {date}",
|
|
||||||
"Release date...": "Дата выхода...",
|
|
||||||
"Remove link": "Убрать ссылку",
|
|
||||||
"repeat": "повторить",
|
|
||||||
"Repeat new password": "Повторите новый пароль",
|
|
||||||
"Reply": "Ответить",
|
|
||||||
"Report": "Пожаловаться",
|
|
||||||
"Report an error": "Сообщить об ошибке",
|
|
||||||
"Reports": "Репортажи",
|
|
||||||
"Required": "Поле обязательно для заполнения",
|
|
||||||
"Resend code": "Выслать подтверждение",
|
|
||||||
"resend confirmation link": "отправить ссылку ещё раз",
|
|
||||||
"Restore password": "Восстановить пароль",
|
|
||||||
"Rules of the journal Discours": "Правила журнала Дискурс",
|
|
||||||
"Save": "Сохранить",
|
|
||||||
"Save draft": "Сохранить черновик",
|
|
||||||
"Save settings": "Сохранить настройки",
|
|
||||||
"Saving...": "Сохраняем...",
|
|
||||||
"Scroll up": "Наверх",
|
|
||||||
"Search": "Поиск",
|
|
||||||
"Search author": "Поиск автора",
|
|
||||||
"Search topic": "Поиск темы",
|
|
||||||
"Sections": "Разделы",
|
|
||||||
"Security": "Безопасность",
|
|
||||||
"Select": "Выбрать",
|
|
||||||
"Self-publishing exists thanks to the help of wonderful people from all over the world. Thank you!": "Самиздат существуют благодаря помощи замечательных людей со всего мира. Спасибо Вам!",
|
|
||||||
"Send": "Отправить",
|
|
||||||
"Send link again": "Прислать ссылку ещё раз",
|
|
||||||
"Settings": "Настройки",
|
|
||||||
"Settings for account, email, password and login methods.": "Настройки аккаунта, почты, пароля и способов входа.",
|
|
||||||
"Share": "Поделиться",
|
|
||||||
"Share publication": "Поделиться публикацией",
|
|
||||||
"Short opening": "Расскажите вашу историю...",
|
|
||||||
"shout": "пост",
|
|
||||||
"shout not found": "публикация не найдена",
|
|
||||||
"Show": "Показать",
|
|
||||||
"Show lyrics": "Текст песни",
|
|
||||||
"Show more": "Читать дальше",
|
|
||||||
"Show table of contents": "Показать главление",
|
|
||||||
"sign in": "войти",
|
|
||||||
"sign up": "зарегистрироваться",
|
|
||||||
"sign up or sign in": "зарегистрироваться или войти",
|
|
||||||
"Site search": "Поиск по сайту",
|
|
||||||
"Slug": "Постоянная ссылка",
|
|
||||||
"slug is used by another user": "Имя уже занято другим пользователем",
|
|
||||||
"Social networks": "Социальные сети",
|
|
||||||
"Society": "Общество",
|
|
||||||
"some authors": "{count} {count, plural, one {автор} few {автора} other {авторов}}",
|
|
||||||
"some comments": "{count, plural, =0 {{count} комментариев} one {{count} комментарий} few {{count} комментария} other {{count} комментариев}}",
|
|
||||||
"some followers": "{count} {count, plural, one {подписчик} few {подписчика} other {подписчиков}}",
|
|
||||||
"some followings": "{count, plural, =0 {нет подписок} one {{count} подписка} few {{count} подписки} other {{count} подписок}}",
|
|
||||||
"Some new comments to your publication": "{commentsCount, plural, one {Новый комментарий} few {{commentsCount} новых комментария} other {{commentsCount} новых комментариев}} к вашей публикации",
|
|
||||||
"Some new replies to your comment": "{commentsCount, plural, one {Новый ответ} few {{commentsCount} новых ответа} other {{commentsCount} новых ответов}} на ваш комментарий к публикации",
|
|
||||||
"some posts": "{count, plural, =0 {нет публикаций} one {{count} публикация} few {{count} публикации} other {{count} публикаций}}",
|
|
||||||
"some shouts": "{count} {count, plural, one {публикация} few {публикации} other {публикаций}}",
|
|
||||||
"some views": "{count} {count, plural, one {просмотр} few {просмотрa} other {просмотров}}",
|
|
||||||
"Something went wrong, check email and password": "Что-то пошло не так. Проверьте адрес электронной почты и пароль",
|
|
||||||
"Something went wrong, please try again": "Что-то пошло не так, попробуйте еще раз",
|
|
||||||
"Song lyrics": "Текст песни...",
|
|
||||||
"Song title": "Название песни",
|
|
||||||
"Soon": "Скоро",
|
|
||||||
"Sorry, this address is already taken, please choose another one.": "Увы, этот адрес уже занят, выберите другой",
|
|
||||||
"Special Projects": "Спецпроекты",
|
|
||||||
"Special projects": "Спецпроекты",
|
|
||||||
"Specify the source and the name of the author": "Укажите источник и имя автора",
|
|
||||||
"Specify your e-mail and we will reply.": "Укажите ваш e-mail и мы обязательно ответим.",
|
|
||||||
"squib": "Подверстка",
|
|
||||||
"Start conversation": "Начать беседу",
|
|
||||||
"Start dialog": "Начать диалог",
|
|
||||||
"Subheader": "Подзаголовок",
|
|
||||||
"Subscribe": "Подписаться",
|
|
||||||
"Subscribe to comments": "Подписаться на комментарии",
|
|
||||||
"Subscribe to the best publications newsletter": "Подпишитесь на рассылку лучших публикаций",
|
|
||||||
"Subscribe us": "Подпишитесь на нас",
|
|
||||||
"Subscribe what you like to tune your personal feed": "Подпишитесь на интересующие вас темы, чтобы настроить вашу персональную ленту и моментально узнавать о новых публикациях и обсуждениях",
|
|
||||||
"Subscribe who you like to tune your personal feed": "Подпишитесь на интересующих вас авторов, чтобы настроить вашу персональную ленту и моментально узнавать о новых публикациях и обсуждениях",
|
|
||||||
"subscriber": "подписчик",
|
|
||||||
"subscriber_rp": "подписчика",
|
|
||||||
"subscribers": "подписчиков",
|
|
||||||
"subscribing...": "Подписка...",
|
|
||||||
"Subscribing...": "Подписываем...",
|
|
||||||
"Subscription": "Подписка",
|
|
||||||
"Subscriptions": "Подписки",
|
|
||||||
"Substrate": "Подложка",
|
|
||||||
"Success": "Успешно",
|
|
||||||
"Successfully authorized": "Авторизация успешна",
|
|
||||||
"Suggest an idea": "Предложить идею",
|
|
||||||
"Support Discours": "Поддержите Дискурс",
|
|
||||||
"Support the project": "Поддержать проект",
|
|
||||||
"Support us": "Помочь журналу",
|
|
||||||
"Terms of use": "Правила сайта",
|
|
||||||
"terms of use": "правилами пользования сайтом",
|
|
||||||
"terms of use keywords": "Discours.io, правила сайта, terms of use",
|
|
||||||
"Text checking": "Проверка текста",
|
|
||||||
"Thank you": "Благодарности",
|
|
||||||
"Thank you for reaching us": "Спасибо, что связались с нами",
|
|
||||||
"Thank you!": "Спасибо Вам!",
|
|
||||||
"The address is already taken": "Адрес уже занят",
|
|
||||||
"The most interesting publications on the topic": "Самые интересные публикации по теме {topicName}",
|
|
||||||
"Thematic table of contents of the magazine. Here you can find all the topics that community authors have written about.": "Тематическое оглавление журнала. Здесь можно найти все темы, о которых писали авторы сообщества.",
|
|
||||||
"Thematic table of contents of the magazine. Here you can find all the topics that the community authors wrote about": "Тематическое оглавление журнала. Здесь можно найти все темы, о которых писали авторы сообщества",
|
|
||||||
"Themes and plots": "Темы и сюжеты",
|
|
||||||
"Theory": "Теории",
|
|
||||||
"There are unsaved changes in your profile settings. Are you sure you want to leave the page without saving?": "В настройках вашего профиля есть несохраненные изменения. Уверены, что хотите покинуть страницу без сохранения?",
|
|
||||||
"There are unsaved changes in your publishing settings. Are you sure you want to leave the page without saving?": "В настройках публикации есть несохраненные изменения. Уверены, что хотите покинуть страницу без сохранения?",
|
|
||||||
"This comment has not yet been rated": "Этот комментарий еще пока никто не оценил",
|
|
||||||
"This content is not published yet": "Содержимое ещё не опубликовано",
|
|
||||||
"This email is": "Этот email",
|
|
||||||
"This email is not verified": "Этот email не подтвержден",
|
|
||||||
"This email is registered": "Этот email уже зарегистрирован",
|
|
||||||
"This email is verified": "Этот email подтвержден",
|
|
||||||
"This functionality is currently not available, we would like to work on this issue. Use the download link.": "В данный момент этот функционал не доступен, бы работаем над этой проблемой. Воспользуйтесь загрузкой по ссылке.",
|
|
||||||
"This month": "За месяц",
|
|
||||||
"This post has not been rated yet": "Эту публикацию еще пока никто не оценил",
|
|
||||||
"This way we ll realize that you re a real person and ll take your vote into account. And you ll see how others voted": "Так мы поймем, что вы реальный человек, и учтем ваш голос. А вы увидите, как проголосовали другие",
|
|
||||||
"This way you ll be able to subscribe to authors, interesting topics and customize your feed": "Так вы сможете подписаться на авторов, интересные темы и настроить свою ленту",
|
|
||||||
"This week": "За неделю",
|
|
||||||
"This year": "За год",
|
|
||||||
"To find publications, art, comments, authors and topics of interest to you, just start typing your query": "Для поиска публикаций, искусства, комментариев, интересных вам авторов и тем, просто начните вводить ваш запрос",
|
|
||||||
"To leave a comment please": "Чтобы оставить комментарий, необходимо",
|
|
||||||
"To write a comment, you must": "Чтобы написать комментарий, необходимо",
|
|
||||||
"today": "сегодня",
|
|
||||||
"Top authors": "Рейтинг авторов",
|
|
||||||
"Top commented": "Самое комментируемое",
|
|
||||||
"Top discussed": "Обсуждаемое",
|
|
||||||
"Top month": "Лучшее за месяц",
|
|
||||||
"Top rated": "Популярное",
|
|
||||||
"Top recent": "Самое новое",
|
|
||||||
"Top topics": "Интересные темы",
|
|
||||||
"Top viewed": "Самое читаемое",
|
|
||||||
"Topic is supported by": "Тему поддерживают",
|
|
||||||
"topicKeywords": "{topic}, Discours.io, статьи, журналистика, исследования",
|
|
||||||
"Topics": "Темы",
|
|
||||||
"topics": "темы",
|
|
||||||
"Topics which supported by author": "Автор поддерживает темы",
|
|
||||||
"try": "попробуйте",
|
|
||||||
"Try to find another way": "Попробуйте найти по-другому",
|
|
||||||
"Unfollow": "Отписаться",
|
|
||||||
"Unfollow the topic": "Отписаться от темы",
|
|
||||||
"Unnamed draft": "Черновик без названия",
|
|
||||||
"Unsubscribing...": "Отписываем...",
|
|
||||||
"Upload": "Загрузить",
|
|
||||||
"Upload error": "Ошибка загрузки",
|
|
||||||
"Upload userpic": "Загрузить аватар",
|
|
||||||
"Upload video": "Загрузить видео",
|
|
||||||
"Uploading image": "Загружаем изображение",
|
|
||||||
"user already exist": "пользователь уже существует",
|
|
||||||
"User was not found": "Пользователь не найден",
|
|
||||||
"Username": "Имя пользователя",
|
|
||||||
"Userpic": "Аватар",
|
|
||||||
"Users": "Пользователи",
|
|
||||||
"verified": "уже подтверждён",
|
|
||||||
"Video": "Видео",
|
|
||||||
"video": "видео",
|
|
||||||
"Video format not supported": "Тип видео не поддерживается",
|
|
||||||
"view": "просмотр",
|
|
||||||
"Views": "Просмотры",
|
|
||||||
"Volounteering": "Волонтёрство",
|
|
||||||
"Want to suggest, discuss or advise something? Share a topic or an idea? Please send us a message!": "Хотите что-то предложить, обсудить или посоветовать? Поделиться темой или идеей? Напишите нам скорее!",
|
|
||||||
"We are working on collaborative editing of articles and in the near future you will have an amazing opportunity - to create together with your colleagues": "Мы работаем над коллаборативным редактированием статей и в ближайшем времени у вас появиться удивительная возможность - творить вместе с коллегами",
|
|
||||||
"We can't find you, check email or": "Не можем вас найти, проверьте адрес электронной почты или",
|
|
||||||
"We couldn't find anything for your request": "Мы не смогли ничего найти по вашему запросу",
|
|
||||||
"We know you, please try to login": "Такой адрес почты уже зарегистрирован, попробуйте залогиниться",
|
|
||||||
"We've sent you a message with a link to enter our website.": "Мы выслали вам письмо с ссылкой на почту. Перейдите по ссылке в письме, чтобы войти на сайт.",
|
|
||||||
"Welcome to Discours": "Добро пожаловать в Дискурс",
|
|
||||||
"Welcome to Discours to add to your bookmarks": "Войдите в Дискурс, чтобы добавить в закладки",
|
|
||||||
"Welcome to Discours to participate in discussions": "Войдите в Дискурс для участия в дискуссиях",
|
|
||||||
"Welcome to Discours to publish articles": "Войдите в Дискурс, чтобы публиковать статьи",
|
|
||||||
"Welcome to Discours to subscribe": "Войдите в Дискурс для подписки на новые публикации",
|
|
||||||
"Welcome to Discours to subscribe to new publications": "Войдите в Дискурс, чтобы подписаться",
|
|
||||||
"Welcome to Discours to vote": "Войдите в Дискурс, чтобы голосовать",
|
|
||||||
"Welcome!": "Добро пожаловать!",
|
|
||||||
"Where": "Откуда",
|
|
||||||
"Why you can earn a hole in your karma and how to receive rays of gratitude for your contribution to discussions in samizdat communities": "За что можно заслужить дырку в карме и как получить лучи благодарности за вклад в дискуссии в сообществах самиздата",
|
|
||||||
"Words": "Слов",
|
|
||||||
"Work with us": "Сотрудничать с Дискурсом",
|
|
||||||
"Write a comment...": "Написать комментарий...",
|
|
||||||
"Write a short introduction": "Напишите краткое вступление",
|
|
||||||
"Write about the topic": "Написать в тему",
|
|
||||||
"Write an article": "Написать статью",
|
|
||||||
"Write comment": "Написать комментарий",
|
|
||||||
"Write good articles, comment\nand it won't be so empty here": "Пишите хорошие статьи, комментируйте,\nи здесь станет не так пусто",
|
|
||||||
"Write message": "Написать сообщение",
|
|
||||||
"Write to us": "Напишите нам",
|
|
||||||
"Write your colleagues name or email": "Напишите имя или e-mail коллеги",
|
|
||||||
"yesterday": "вчера",
|
|
||||||
"You can": "Вы можете",
|
|
||||||
"You can download multiple tracks at once in .mp3, .wav or .flac formats": "Можно загрузить сразу несколько треков в форматах .mp3, .wav или .flac",
|
|
||||||
"You can now login using your new password": "Теперь вы можете входить с помощью нового пароля",
|
|
||||||
"You can't edit this post": "Вы не можете редактировать этот материал",
|
|
||||||
"You was successfully authorized": "Вы были успешно авторизованы",
|
|
||||||
"You ll be able to participate in discussions, rate others' comments and learn about new responses": "Вы сможете участвовать в обсуждениях, оценивать комментарии других и узнавать о новых ответах",
|
|
||||||
"You've confirmed email": "Вы подтвердили почту",
|
|
||||||
"You've reached a non-existed page": "Вы попали на несуществующую страницу",
|
|
||||||
"You've successfully logged out": "Вы успешно вышли из аккаунта",
|
|
||||||
"Your contact for answer": "Ваш контакт для обратной связи",
|
|
||||||
"Your email": "Ваш email",
|
|
||||||
"Your name will appear on your profile page and as your signature in publications, comments and responses.": "Ваше имя появится на странице вашего профиля и как ваша подпись в публикациях, комментариях и откликах"
|
|
||||||
}
|
|
|
@ -4,6 +4,7 @@ import { FileRoutes } from '@solidjs/start/router'
|
||||||
import { type JSX, Suspense } from 'solid-js'
|
import { type JSX, Suspense } from 'solid-js'
|
||||||
|
|
||||||
import { Loading } from './components/_shared/Loading'
|
import { Loading } from './components/_shared/Loading'
|
||||||
|
import { AuthorsProvider } from './context/authors'
|
||||||
import { EditorProvider } from './context/editor'
|
import { EditorProvider } from './context/editor'
|
||||||
import { FeedProvider } from './context/feed'
|
import { FeedProvider } from './context/feed'
|
||||||
import { GraphQLClientProvider } from './context/graphql'
|
import { GraphQLClientProvider } from './context/graphql'
|
||||||
|
@ -24,7 +25,9 @@ export const Providers = (props: { children?: JSX.Element }) => {
|
||||||
<Meta name="viewport" content="width=device-width, initial-scale=1" />
|
<Meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<UIProvider>
|
<UIProvider>
|
||||||
<EditorProvider>
|
<EditorProvider>
|
||||||
<Suspense fallback={<Loading />}>{props.children}</Suspense>
|
<AuthorsProvider>
|
||||||
|
<Suspense fallback={<Loading />}>{props.children}</Suspense>
|
||||||
|
</AuthorsProvider>
|
||||||
</EditorProvider>
|
</EditorProvider>
|
||||||
</UIProvider>
|
</UIProvider>
|
||||||
</MetaProvider>
|
</MetaProvider>
|
||||||
|
|
|
@ -27,6 +27,16 @@ img {
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutBody {
|
.shoutBody {
|
||||||
|
@include media-breakpoint-up(sm) {
|
||||||
|
:global(.width-30) {
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.width-50) {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
|
|
||||||
|
@ -65,6 +75,16 @@ img {
|
||||||
|
|
||||||
blockquote[data-type='quote'],
|
blockquote[data-type='quote'],
|
||||||
ta-quotation {
|
ta-quotation {
|
||||||
|
@include media-breakpoint-up(sm) {
|
||||||
|
&[data-float='left'] {
|
||||||
|
margin-right: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-float='right'] {
|
||||||
|
margin-left: 1.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
border: solid #000;
|
border: solid #000;
|
||||||
border-width: 0 0 0 2px;
|
border-width: 0 0 0 2px;
|
||||||
clear: both;
|
clear: both;
|
||||||
|
@ -78,21 +98,11 @@ img {
|
||||||
&[data-float='right'] {
|
&[data-float='right'] {
|
||||||
@include font-size(2.2rem);
|
@include font-size(2.2rem);
|
||||||
|
|
||||||
line-height: 1.4;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
@include media-breakpoint-up(sm) {
|
||||||
clear: none;
|
clear: none;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
line-height: 1.4;
|
||||||
&[data-float='left'] {
|
|
||||||
margin-right: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-float='right'] {
|
|
||||||
margin-left: 1.5em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
|
@ -106,17 +116,17 @@ img {
|
||||||
ta-border-sub {
|
ta-border-sub {
|
||||||
@include font-size(1.4rem);
|
@include font-size(1.4rem);
|
||||||
|
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
margin: 3.2rem -8.3333%;
|
||||||
|
padding: 3.2rem 8.3333%;
|
||||||
|
}
|
||||||
|
|
||||||
background: #f1f2f3;
|
background: #f1f2f3;
|
||||||
clear: both;
|
clear: both;
|
||||||
display: block;
|
display: block;
|
||||||
margin: 3.2rem 0;
|
margin: 3.2rem 0;
|
||||||
padding: 3.2rem;
|
padding: 3.2rem;
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
|
||||||
margin: 3.2rem -8.3333%;
|
|
||||||
padding: 3.2rem 8.3333%;
|
|
||||||
}
|
|
||||||
|
|
||||||
p:last-child {
|
p:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
@ -194,16 +204,6 @@ img {
|
||||||
margin: 0 8.3333% 1.5em 0;
|
margin: 0 8.3333% 1.5em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
|
||||||
:global(.width-30) {
|
|
||||||
width: 30%;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.width-50) {
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.img-align-left.width-50) {
|
:global(.img-align-left.width-50) {
|
||||||
@include media-breakpoint-up(xl) {
|
@include media-breakpoint-up(xl) {
|
||||||
margin-left: -16.6666%;
|
margin-left: -16.6666%;
|
||||||
|
@ -313,20 +313,24 @@ img {
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutStats {
|
.shoutStats {
|
||||||
|
@include media-breakpoint-down(lg) {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
border-top: 4px solid #000;
|
border-top: 4px solid #000;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
padding: 3rem 0 0;
|
padding: 3rem 0 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
@include media-breakpoint-down(lg) {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutStatsItem {
|
.shoutStatsItem {
|
||||||
@include font-size(1.5rem);
|
@include font-size(1.5rem);
|
||||||
|
|
||||||
|
@include media-breakpoint-up(xl) {
|
||||||
|
margin-right: 3.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -334,10 +338,6 @@ img {
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
@include media-breakpoint-up(xl) {
|
|
||||||
margin-right: 3.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-right: 0.2em;
|
margin-right: 0.2em;
|
||||||
|
@ -379,11 +379,11 @@ img {
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutStatsItemBookmarks {
|
.shoutStatsItemBookmarks {
|
||||||
margin-left: auto;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(lg) {
|
@include media-breakpoint-up(lg) {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutStatsItemInner {
|
.shoutStatsItemInner {
|
||||||
|
@ -408,6 +408,15 @@ img {
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutStatsItemAdditionalData {
|
.shoutStatsItemAdditionalData {
|
||||||
|
@include media-breakpoint-down(lg) {
|
||||||
|
flex: 1 100%;
|
||||||
|
order: 9;
|
||||||
|
|
||||||
|
.shoutStatsItemAdditionalDataItem {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
color: rgb(0 0 0 / 40%);
|
color: rgb(0 0 0 / 40%);
|
||||||
cursor: default;
|
cursor: default;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
@ -418,24 +427,9 @@ img {
|
||||||
opacity: 0.4;
|
opacity: 0.4;
|
||||||
height: 2rem;
|
height: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-down(lg) {
|
|
||||||
flex: 1 100%;
|
|
||||||
order: 9;
|
|
||||||
|
|
||||||
.shoutStatsItemAdditionalDataItem {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutStatsItemViews {
|
.shoutStatsItemViews {
|
||||||
color: rgb(0 0 0 / 40%);
|
|
||||||
cursor: default;
|
|
||||||
font-weight: normal;
|
|
||||||
margin-left: auto;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(lg) {
|
@include media-breakpoint-down(lg) {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
flex: 1 40%;
|
flex: 1 40%;
|
||||||
|
@ -449,6 +443,12 @@ img {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
color: rgb(0 0 0 / 40%);
|
||||||
|
cursor: default;
|
||||||
|
font-weight: normal;
|
||||||
|
margin-left: auto;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutStatsItemLabel {
|
.shoutStatsItemLabel {
|
||||||
|
@ -457,11 +457,11 @@ img {
|
||||||
}
|
}
|
||||||
|
|
||||||
.commentsTextLabel {
|
.commentsTextLabel {
|
||||||
display: none;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
@include media-breakpoint-up(sm) {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutStatsItemCount {
|
.shoutStatsItemCount {
|
||||||
|
@ -471,6 +471,12 @@ img {
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutStatsItemAdditionalDataItem {
|
.shoutStatsItemAdditionalDataItem {
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
&:first-child {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
||||||
|
@ -478,12 +484,6 @@ img {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
|
||||||
&:first-child {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.topicsList {
|
.topicsList {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Show, createSignal } from 'solid-js'
|
import { Show, createSignal } from 'solid-js'
|
||||||
|
|
||||||
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
|
import { Image } from '~/components/_shared/Image'
|
||||||
|
import { Topic } from '~/graphql/schema/core.gen'
|
||||||
import { MediaItem } from '~/types/mediaitem'
|
import { MediaItem } from '~/types/mediaitem'
|
||||||
import { Topic } from '../../../graphql/schema/core.gen'
|
|
||||||
import { CardTopic } from '../../Feed/CardTopic'
|
import { CardTopic } from '../../Feed/CardTopic'
|
||||||
import { Icon } from '../../_shared/Icon'
|
|
||||||
import { Image } from '../../_shared/Image'
|
|
||||||
|
|
||||||
import styles from './AudioHeader.module.scss'
|
import styles from './AudioHeader.module.scss'
|
||||||
|
|
||||||
|
|
|
@ -3,27 +3,32 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.playerHeader {
|
.playerHeader {
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
@include media-breakpoint-down(sm) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.playerTitle {
|
.playerTitle {
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
max-width: 50%;
|
max-width: 50%;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.playerControls {
|
.playerControls {
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
min-width: 160px;
|
min-width: 160px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -42,11 +47,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.playButton {
|
.playButton {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Show, createSignal } from 'solid-js'
|
import { Show, createSignal } from 'solid-js'
|
||||||
import { useOutsideClickHandler } from '../../../utils/useOutsideClickHandler'
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
import { Icon } from '../../_shared/Icon'
|
import { useOutsideClickHandler } from '~/lib/useOutsideClickHandler'
|
||||||
|
|
||||||
import { MediaItem } from '~/types/mediaitem'
|
import { MediaItem } from '~/types/mediaitem'
|
||||||
import styles from './AudioPlayer.module.scss'
|
import styles from './AudioPlayer.module.scss'
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import { For, Show, createSignal, lazy } from 'solid-js'
|
import { For, Show, createSignal, lazy } from 'solid-js'
|
||||||
|
|
||||||
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
|
import { Popover } from '~/components/_shared/Popover'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { MediaItem } from '~/types/mediaitem'
|
import { MediaItem } from '~/types/mediaitem'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { descFromBody } from '~/utils/meta'
|
||||||
import { getDescription } from '../../../utils/meta'
|
|
||||||
import { Icon } from '../../_shared/Icon'
|
|
||||||
import { Popover } from '../../_shared/Popover'
|
|
||||||
import { SharePopup, getShareUrl } from '../SharePopup'
|
import { SharePopup, getShareUrl } from '../SharePopup'
|
||||||
|
|
||||||
import styles from './AudioPlayer.module.scss'
|
import styles from './AudioPlayer.module.scss'
|
||||||
|
|
||||||
const SimplifiedEditor = lazy(() => import('../../Editor/SimplifiedEditor'))
|
const SimplifiedEditor = lazy(() => import('../../Editor/SimplifiedEditor'))
|
||||||
const GrowingTextarea = lazy(() => import('../../_shared/GrowingTextarea/GrowingTextarea'))
|
const GrowingTextarea = lazy(() => import('~/components/_shared/GrowingTextarea/GrowingTextarea'))
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
media: MediaItem[]
|
media: MediaItem[]
|
||||||
|
@ -137,7 +137,7 @@ export const PlayerPlaylist = (props: Props) => {
|
||||||
>
|
>
|
||||||
<SharePopup
|
<SharePopup
|
||||||
title={mi.title}
|
title={mi.title}
|
||||||
description={getDescription(props.body || '')}
|
description={descFromBody(props.body || '')}
|
||||||
imageUrl={mi.pic || ''}
|
imageUrl={mi.pic || ''}
|
||||||
shareUrl={getShareUrl({ pathname: `/${props.articleSlug}` })}
|
shareUrl={getShareUrl({ pathname: `/${props.articleSlug}` })}
|
||||||
trigger={
|
trigger={
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
.comment {
|
.comment {
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
margin: 0 0 0.5em;
|
margin: 0 0 0.5em;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
transition: background-color 0.3s;
|
transition: background-color 0.3s;
|
||||||
position: relative;
|
position: relative;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.isNew {
|
&.isNew {
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
background: rgb(38 56 217 / 5%);
|
background: rgb(38 56 217 / 5%);
|
||||||
|
@ -193,9 +193,6 @@
|
||||||
.articleLink {
|
.articleLink {
|
||||||
@include font-size(1.2rem);
|
@include font-size(1.2rem);
|
||||||
|
|
||||||
flex: 0 0 50%;
|
|
||||||
margin-right: 2em;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(md) {
|
@include media-breakpoint-down(md) {
|
||||||
margin: 0.3em 0 0.5em;
|
margin: 0.3em 0 0.5em;
|
||||||
}
|
}
|
||||||
|
@ -208,20 +205,25 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flex: 0 0 50%;
|
||||||
|
margin-right: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.articleLinkIcon {
|
.articleLinkIcon {
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
width: 1em;
|
width: 1em;
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
|
||||||
margin-left: 1em;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.commentDates {
|
.commentDates {
|
||||||
|
@include font-size(1.2rem);
|
||||||
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
@ -231,8 +233,6 @@
|
||||||
margin: 0 1em 4px 0;
|
margin: 0 1em 4px 0;
|
||||||
color: rgb(0 0 0 / 30%);
|
color: rgb(0 0 0 / 30%);
|
||||||
|
|
||||||
@include font-size(1.2rem);
|
|
||||||
|
|
||||||
.date {
|
.date {
|
||||||
.icon {
|
.icon {
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
|
@ -246,13 +246,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.commentDetails {
|
.commentDetails {
|
||||||
padding: 1rem 0.2rem 0;
|
|
||||||
margin-bottom: 1.2rem;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
padding: 1rem 0.2rem 0;
|
||||||
|
margin-bottom: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compactUserpic {
|
.compactUserpic {
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
import { A } from '@solidjs/router'
|
import { A } from '@solidjs/router'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Show, Suspense, createMemo, createSignal, lazy } from 'solid-js'
|
import { For, Show, Suspense, createMemo, createSignal, lazy } from 'solid-js'
|
||||||
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
|
import { ShowIfAuthenticated } from '~/components/_shared/ShowIfAuthenticated'
|
||||||
import { useGraphQL } from '~/context/graphql'
|
import { useGraphQL } from '~/context/graphql'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
|
import { useReactions } from '~/context/reactions'
|
||||||
|
import { useSession } from '~/context/session'
|
||||||
import { useSnackbar, useUI } from '~/context/ui'
|
import { useSnackbar, useUI } from '~/context/ui'
|
||||||
import deleteReactionMutation from '~/graphql/mutation/core/reaction-destroy'
|
import deleteReactionMutation from '~/graphql/mutation/core/reaction-destroy'
|
||||||
import { useLocalize } from '../../../context/localize'
|
|
||||||
import { useReactions } from '../../../context/reactions'
|
|
||||||
import { useSession } from '../../../context/session'
|
|
||||||
import {
|
import {
|
||||||
Author,
|
Author,
|
||||||
MutationCreate_ReactionArgs,
|
MutationCreate_ReactionArgs,
|
||||||
MutationUpdate_ReactionArgs,
|
MutationUpdate_ReactionArgs,
|
||||||
Reaction,
|
Reaction,
|
||||||
ReactionKind
|
ReactionKind
|
||||||
} from '../../../graphql/schema/core.gen'
|
} from '~/graphql/schema/core.gen'
|
||||||
import { AuthorLink } from '../../Author/AuthorLink'
|
import { AuthorLink } from '../../Author/AuthorLink'
|
||||||
import { Userpic } from '../../Author/Userpic'
|
import { Userpic } from '../../Author/Userpic'
|
||||||
import { Icon } from '../../_shared/Icon'
|
|
||||||
import { ShowIfAuthenticated } from '../../_shared/ShowIfAuthenticated'
|
|
||||||
import { CommentDate } from '../CommentDate'
|
import { CommentDate } from '../CommentDate'
|
||||||
import { RatingControl as CommentRatingControl } from '../RatingControl'
|
import { RatingControl as CommentRatingControl } from '../RatingControl'
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ export const Comment = (props: Props) => {
|
||||||
{/* class={clsx(styles.commentControl, styles.commentControlComplain)}*/}
|
{/* class={clsx(styles.commentControl, styles.commentControlComplain)}*/}
|
||||||
{/* onClick={() => showModal('reportComment')}*/}
|
{/* onClick={() => showModal('reportComment')}*/}
|
||||||
{/*>*/}
|
{/*>*/}
|
||||||
{/* {t('Report')}*/}
|
{/* {t('Complain')}*/}
|
||||||
{/*</button>*/}
|
{/*</button>*/}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import type { Reaction } from '../../../graphql/schema/core.gen'
|
import type { Reaction } from '~/graphql/schema/core.gen'
|
||||||
|
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
|
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
|
|
||||||
import styles from './CommentDate.module.scss'
|
import styles from './CommentDate.module.scss'
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Show, createMemo, createSignal, lazy, onMount } from 'solid-js'
|
import { For, Show, createMemo, createSignal, lazy, onMount } from 'solid-js'
|
||||||
|
|
||||||
import { useLocalize } from '../../context/localize'
|
import { useFeed } from '~/context/feed'
|
||||||
import { useReactions } from '../../context/reactions'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useSession } from '../../context/session'
|
import { useReactions } from '~/context/reactions'
|
||||||
import { Author, Reaction, ReactionKind, ReactionSort } from '../../graphql/schema/core.gen'
|
import { useSession } from '~/context/session'
|
||||||
import { byCreated, byStat } from '../../utils/sortby'
|
import { Author, Reaction, ReactionKind, ReactionSort } from '~/graphql/schema/core.gen'
|
||||||
|
import { byCreated, byStat } from '~/lib/sort'
|
||||||
|
import { SortFunction } from '~/types/common'
|
||||||
import { Button } from '../_shared/Button'
|
import { Button } from '../_shared/Button'
|
||||||
import { ShowIfAuthenticated } from '../_shared/ShowIfAuthenticated'
|
import { ShowIfAuthenticated } from '../_shared/ShowIfAuthenticated'
|
||||||
|
|
||||||
import { Comment } from './Comment'
|
|
||||||
|
|
||||||
import { SortFunction } from '~/context/authors'
|
|
||||||
import { useFeed } from '../../context/feed'
|
|
||||||
import styles from './Article.module.scss'
|
import styles from './Article.module.scss'
|
||||||
|
import { Comment } from './Comment'
|
||||||
|
|
||||||
const SimplifiedEditor = lazy(() => import('../Editor/SimplifiedEditor'))
|
const SimplifiedEditor = lazy(() => import('../Editor/SimplifiedEditor'))
|
||||||
|
|
||||||
|
@ -52,10 +50,10 @@ export const CommentsTree = (props: Props) => {
|
||||||
})
|
})
|
||||||
const { seen } = useFeed()
|
const { seen } = useFeed()
|
||||||
const shoutLastSeen = createMemo(() => seen()[props.shoutSlug] ?? 0)
|
const shoutLastSeen = createMemo(() => seen()[props.shoutSlug] ?? 0)
|
||||||
const currentDate = new Date()
|
|
||||||
const setCookie = () => localStorage.setItem(`${props.shoutSlug}`, `${currentDate}`)
|
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
const currentDate = new Date()
|
||||||
|
const setCookie = () => localStorage?.setItem(`${props.shoutSlug}`, `${currentDate}`)
|
||||||
if (!shoutLastSeen()) {
|
if (!shoutLastSeen()) {
|
||||||
setCookie()
|
setCookie()
|
||||||
} else if (currentDate.getTime() > shoutLastSeen()) {
|
} else if (currentDate.getTime() > shoutLastSeen()) {
|
||||||
|
@ -98,7 +96,7 @@ export const CommentsTree = (props: Props) => {
|
||||||
<h2 class={styles.commentsHeader}>
|
<h2 class={styles.commentsHeader}>
|
||||||
{t('Comments')} {comments().length.toString() || ''}
|
{t('Comments')} {comments().length.toString() || ''}
|
||||||
<Show when={newReactions().length > 0}>
|
<Show when={newReactions().length > 0}>
|
||||||
<span class={styles.newReactions}> +{newReactions().length}</span>
|
<span class={styles.newReactions}>{` +${newReactions().length}`}</span>
|
||||||
</Show>
|
</Show>
|
||||||
</h2>
|
</h2>
|
||||||
<Show when={comments().length > 0}>
|
<Show when={comments().length > 0}>
|
||||||
|
@ -150,7 +148,7 @@ export const CommentsTree = (props: Props) => {
|
||||||
<a href="?m=auth&mode=register" class={styles.link}>
|
<a href="?m=auth&mode=register" class={styles.link}>
|
||||||
{t('sign up')}
|
{t('sign up')}
|
||||||
</a>{' '}
|
</a>{' '}
|
||||||
{t('or')}
|
{t('or')}{' '}
|
||||||
<a href="?m=auth&mode=login" class={styles.link}>
|
<a href="?m=auth&mode=login" class={styles.link}>
|
||||||
{t('sign in')}
|
{t('sign in')}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -1,44 +1,41 @@
|
||||||
import { createPopper } from '@popperjs/core'
|
import { createPopper } from '@popperjs/core'
|
||||||
|
import { Link } from '@solidjs/meta'
|
||||||
|
import { A, useSearchParams } from '@solidjs/router'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
// import { install } from 'ga-gtag'
|
|
||||||
import { For, Show, createEffect, createMemo, createSignal, on, onCleanup, onMount } from 'solid-js'
|
import { For, Show, createEffect, createMemo, createSignal, on, onCleanup, onMount } from 'solid-js'
|
||||||
import { isServer } from 'solid-js/web'
|
import { isServer } from 'solid-js/web'
|
||||||
|
import { useFeed } from '~/context/feed'
|
||||||
import { Link, Meta } from '@solidjs/meta'
|
import { useLocalize } from '~/context/localize'
|
||||||
|
import { useReactions } from '~/context/reactions'
|
||||||
|
import { useSession } from '~/context/session'
|
||||||
import { DEFAULT_HEADER_OFFSET, useUI } from '~/context/ui'
|
import { DEFAULT_HEADER_OFFSET, useUI } from '~/context/ui'
|
||||||
|
import type { Author, Maybe, Shout, Topic } from '~/graphql/schema/core.gen'
|
||||||
|
import { processPrepositions } from '~/intl/prepositions'
|
||||||
|
import { isCyrillic } from '~/intl/translate'
|
||||||
|
import { getImageUrl } from '~/lib/getThumbUrl'
|
||||||
import { MediaItem } from '~/types/mediaitem'
|
import { MediaItem } from '~/types/mediaitem'
|
||||||
import { useLocalize } from '../../context/localize'
|
import { capitalize } from '~/utils/capitalize'
|
||||||
import { useReactions } from '../../context/reactions'
|
|
||||||
import { useSession } from '../../context/session'
|
|
||||||
import type { Author, Maybe, Shout, Topic } from '../../graphql/schema/core.gen'
|
|
||||||
import { capitalize } from '../../utils/capitalize'
|
|
||||||
import { getImageUrl, getOpenGraphImageUrl } from '../../utils/getImageUrl'
|
|
||||||
import { getDescription, getKeywords } from '../../utils/meta'
|
|
||||||
import { isCyrillic } from '../../utils/translate'
|
|
||||||
import { AuthorBadge } from '../Author/AuthorBadge'
|
import { AuthorBadge } from '../Author/AuthorBadge'
|
||||||
import { CardTopic } from '../Feed/CardTopic'
|
import { CardTopic } from '../Feed/CardTopic'
|
||||||
import { FeedArticlePopup } from '../Feed/FeedArticlePopup'
|
import { FeedArticlePopup } from '../Feed/FeedArticlePopup'
|
||||||
import { Modal } from '../Nav/Modal'
|
import stylesHeader from '../HeaderNav/Header.module.scss'
|
||||||
import { TableOfContents } from '../TableOfContents'
|
|
||||||
import { Icon } from '../_shared/Icon'
|
import { Icon } from '../_shared/Icon'
|
||||||
import { Image } from '../_shared/Image'
|
import { Image } from '../_shared/Image'
|
||||||
import { InviteMembers } from '../_shared/InviteMembers'
|
import { InviteMembers } from '../_shared/InviteMembers'
|
||||||
import { Lightbox } from '../_shared/Lightbox'
|
import { Lightbox } from '../_shared/Lightbox'
|
||||||
|
import { Modal } from '../_shared/Modal'
|
||||||
import { Popover } from '../_shared/Popover'
|
import { Popover } from '../_shared/Popover'
|
||||||
import { ShareModal } from '../_shared/ShareModal'
|
import { ShareModal } from '../_shared/ShareModal'
|
||||||
import { ImageSwiper } from '../_shared/SolidSwiper'
|
import { ImageSwiper } from '../_shared/SolidSwiper'
|
||||||
|
import { TableOfContents } from '../_shared/TableOfContents'
|
||||||
import { VideoPlayer } from '../_shared/VideoPlayer'
|
import { VideoPlayer } from '../_shared/VideoPlayer'
|
||||||
|
import styles from './Article.module.scss'
|
||||||
import { AudioHeader } from './AudioHeader'
|
import { AudioHeader } from './AudioHeader'
|
||||||
import { AudioPlayer } from './AudioPlayer'
|
import { AudioPlayer } from './AudioPlayer'
|
||||||
import { CommentsTree } from './CommentsTree'
|
import { CommentsTree } from './CommentsTree'
|
||||||
import { RatingControl as ShoutRatingControl } from './RatingControl'
|
import { RatingControl as ShoutRatingControl } from './RatingControl'
|
||||||
import { SharePopup, getShareUrl } from './SharePopup'
|
import { SharePopup, getShareUrl } from './SharePopup'
|
||||||
|
|
||||||
import { A, useSearchParams } from '@solidjs/router'
|
|
||||||
import { useFeed } from '~/context/feed'
|
|
||||||
import stylesHeader from '../Nav/Header/Header.module.scss'
|
|
||||||
import styles from './Article.module.scss'
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
article: Shout
|
article: Shout
|
||||||
scrollToComments?: boolean
|
scrollToComments?: boolean
|
||||||
|
@ -57,15 +54,17 @@ export type ArticlePageSearchParams = {
|
||||||
|
|
||||||
const scrollTo = (el: HTMLElement) => {
|
const scrollTo = (el: HTMLElement) => {
|
||||||
const { top } = el.getBoundingClientRect()
|
const { top } = el.getBoundingClientRect()
|
||||||
if (window)
|
|
||||||
window.scrollTo({
|
window?.scrollTo({
|
||||||
top: top + window.scrollY - DEFAULT_HEADER_OFFSET,
|
top: top + window.scrollY - DEFAULT_HEADER_OFFSET,
|
||||||
left: 0,
|
left: 0,
|
||||||
behavior: 'smooth'
|
behavior: 'smooth'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const imgSrcRegExp = /<img[^>]+src\s*=\s*["']([^"']+)["']/gi
|
const imgSrcRegExp = /<img[^>]+src\s*=\s*["']([^"']+)["']/gi
|
||||||
|
const COMMENTS_PER_PAGE = 30
|
||||||
|
const VOTES_PER_PAGE = 50
|
||||||
|
|
||||||
export const FullArticle = (props: Props) => {
|
export const FullArticle = (props: Props) => {
|
||||||
const [searchParams, changeSearchParams] = useSearchParams<ArticlePageSearchParams>()
|
const [searchParams, changeSearchParams] = useSearchParams<ArticlePageSearchParams>()
|
||||||
|
@ -78,25 +77,45 @@ export const FullArticle = (props: Props) => {
|
||||||
const { session, requireAuthentication } = useSession()
|
const { session, requireAuthentication } = useSession()
|
||||||
const author = createMemo<Author>(() => session()?.user?.app_data?.profile as Author)
|
const author = createMemo<Author>(() => session()?.user?.app_data?.profile as Author)
|
||||||
const { addSeen } = useFeed()
|
const { addSeen } = useFeed()
|
||||||
|
const formattedDate = createMemo(() => formatDate(new Date((props.article.published_at || 0) * 1000)))
|
||||||
|
|
||||||
const formattedDate = createMemo(() => formatDate(new Date((props.article?.published_at || 0) * 1000)))
|
const [pages, setPages] = createSignal<Record<string, number>>({})
|
||||||
|
createEffect(
|
||||||
|
on(
|
||||||
|
pages,
|
||||||
|
async (p: Record<string, number>) => {
|
||||||
|
await loadReactionsBy({
|
||||||
|
by: { shout: props.article.slug, comment: true },
|
||||||
|
limit: COMMENTS_PER_PAGE,
|
||||||
|
offset: COMMENTS_PER_PAGE * p.comments || 0
|
||||||
|
})
|
||||||
|
await loadReactionsBy({
|
||||||
|
by: { shout: props.article.slug, rating: true },
|
||||||
|
limit: VOTES_PER_PAGE,
|
||||||
|
offset: VOTES_PER_PAGE * p.rating || 0
|
||||||
|
})
|
||||||
|
setIsReactionsLoaded(true)
|
||||||
|
},
|
||||||
|
{ defer: true }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
const canEdit = createMemo(
|
const canEdit = createMemo(
|
||||||
() =>
|
() =>
|
||||||
Boolean(author()?.id) &&
|
Boolean(author()?.id) &&
|
||||||
(props.article?.authors?.some((a) => Boolean(a) && a?.id === author().id) ||
|
(props.article.authors?.some((a) => Boolean(a) && a?.id === author().id) ||
|
||||||
props.article?.created_by?.id === author().id ||
|
props.article.created_by?.id === author().id ||
|
||||||
session()?.user?.roles?.includes('editor'))
|
session()?.user?.roles?.includes('editor'))
|
||||||
)
|
)
|
||||||
|
|
||||||
const mainTopic = createMemo(() => {
|
const mainTopic = createMemo(() => {
|
||||||
const mainTopicSlug = (props.article?.topics?.length || 0) > 0 ? props.article.main_topic : null
|
const mainTopicSlug = (props.article.topics?.length || 0) > 0 ? props.article.main_topic : null
|
||||||
const mt = props.article.topics?.find((tpc: Maybe<Topic>) => tpc?.slug === mainTopicSlug)
|
const mt = props.article.topics?.find((tpc: Maybe<Topic>) => tpc?.slug === mainTopicSlug)
|
||||||
if (mt) {
|
if (mt) {
|
||||||
mt.title = lang() === 'en' ? capitalize(mt.slug.replace(/-/, ' ')) : mt.title
|
mt.title = lang() === 'en' ? capitalize(mt.slug.replace(/-/, ' ')) : mt.title
|
||||||
return mt
|
return mt
|
||||||
}
|
}
|
||||||
return props.article?.topics?.[0]
|
return props.article.topics?.[0]
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleBookmarkButtonClick = (ev: MouseEvent | undefined) => {
|
const handleBookmarkButtonClick = (ev: MouseEvent | undefined) => {
|
||||||
|
@ -109,17 +128,17 @@ export const FullArticle = (props: Props) => {
|
||||||
const body = createMemo(() => {
|
const body = createMemo(() => {
|
||||||
if (props.article.layout === 'literature') {
|
if (props.article.layout === 'literature') {
|
||||||
try {
|
try {
|
||||||
if (props.article?.media) {
|
if (props.article.media) {
|
||||||
const media = JSON.parse(props.article.media)
|
const media = JSON.parse(props.article.media)
|
||||||
if (media.length > 0) {
|
if (media.length > 0) {
|
||||||
return media[0].body
|
return processPrepositions(media[0].body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return props.article.body
|
return processPrepositions(props.article.body) || ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const imageUrls = createMemo(() => {
|
const imageUrls = createMemo(() => {
|
||||||
|
@ -143,13 +162,7 @@ export const FullArticle = (props: Props) => {
|
||||||
return Array.from(imageElements).map((img) => img.src)
|
return Array.from(imageElements).map((img) => img.src)
|
||||||
})
|
})
|
||||||
|
|
||||||
const media = createMemo<MediaItem[]>(() => {
|
const media = createMemo<MediaItem[]>(() => JSON.parse(props.article.media || '[]'))
|
||||||
try {
|
|
||||||
return JSON.parse(props.article?.media || '[]')
|
|
||||||
} catch {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
let commentsRef: HTMLDivElement | undefined
|
let commentsRef: HTMLDivElement | undefined
|
||||||
|
|
||||||
|
@ -270,7 +283,8 @@ export const FullArticle = (props: Props) => {
|
||||||
// Check iframes size
|
// Check iframes size
|
||||||
let articleContainer: HTMLElement | undefined
|
let articleContainer: HTMLElement | undefined
|
||||||
const updateIframeSizes = () => {
|
const updateIframeSizes = () => {
|
||||||
if (!(articleContainer && props.article.body && window)) return
|
if (!window) return
|
||||||
|
if (!(articleContainer && props.article.body)) return
|
||||||
const iframes = articleContainer?.querySelectorAll('iframe')
|
const iframes = articleContainer?.querySelectorAll('iframe')
|
||||||
if (!iframes) return
|
if (!iframes) return
|
||||||
const containerWidth = articleContainer?.offsetWidth
|
const containerWidth = articleContainer?.offsetWidth
|
||||||
|
@ -306,67 +320,25 @@ export const FullArticle = (props: Props) => {
|
||||||
// install('G-LQ4B87H8C2')
|
// install('G-LQ4B87H8C2')
|
||||||
await loadReactionsBy({ by: { shout: props.article.slug } })
|
await loadReactionsBy({ by: { shout: props.article.slug } })
|
||||||
addSeen(props.article.slug)
|
addSeen(props.article.slug)
|
||||||
setIsReactionsLoaded(true)
|
|
||||||
document.title = props.article.title
|
document.title = props.article.title
|
||||||
|
updateIframeSizes()
|
||||||
window?.addEventListener('resize', updateIframeSizes)
|
window?.addEventListener('resize', updateIframeSizes)
|
||||||
|
|
||||||
onCleanup(() => window.removeEventListener('resize', updateIframeSizes))
|
onCleanup(() => window.removeEventListener('resize', updateIframeSizes))
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
if (props.scrollToComments && commentsRef) {
|
|
||||||
scrollTo(commentsRef)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
if (searchParams?.scrollTo === 'comments' && commentsRef) {
|
|
||||||
requestAnimationFrame(() => commentsRef && scrollTo(commentsRef))
|
|
||||||
changeSearchParams({ scrollTo: undefined })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
createEffect(
|
createEffect(() => props.scrollToComments && commentsRef && scrollTo(commentsRef))
|
||||||
on(
|
createEffect(() => {
|
||||||
() => props.article,
|
if (searchParams?.scrollTo === 'comments' && commentsRef) {
|
||||||
async (shout: Shout) => {
|
requestAnimationFrame(() => commentsRef && scrollTo(commentsRef))
|
||||||
setIsReactionsLoaded(false)
|
changeSearchParams({ scrollTo: undefined })
|
||||||
const rrr = await loadReactionsBy({ by: { shout: shout?.slug } })
|
}
|
||||||
setRatings((_) => rrr.filter((r) => ['LIKE', 'DISLIKE'].includes(r.kind)))
|
|
||||||
setIsReactionsLoaded(true)
|
|
||||||
},
|
|
||||||
{ defer: true },
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
const cover = props.article.cover ?? 'production/image/logo_image.png'
|
|
||||||
const ogImage = getOpenGraphImageUrl(cover, {
|
|
||||||
title: props.article.title,
|
|
||||||
topic: mainTopic()?.title || '',
|
|
||||||
author: props.article?.authors?.[0]?.name || '',
|
|
||||||
width: 1200
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const description = getDescription(props.article.description || body() || media()[0]?.body)
|
const shareUrl = createMemo(() => getShareUrl({ pathname: `/${props.article.slug || ''}` }))
|
||||||
const ogTitle = props.article.title
|
const getAuthorName = (a: Author) =>
|
||||||
const keywords = getKeywords(props.article)
|
lang() === 'en' && isCyrillic(a.name || '') ? capitalize(a.slug.replace(/-/, ' ')) : a.name
|
||||||
const shareUrl = getShareUrl({ pathname: `/${props.article.slug}` })
|
|
||||||
const getAuthorName = (a: Author) => {
|
|
||||||
return lang() === 'en' && isCyrillic(a.name || '') ? capitalize(a.slug.replace(/-/, ' ')) : a.name
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Meta name="descprition" content={description} />
|
|
||||||
<Meta name="keywords" content={keywords} />
|
|
||||||
<Meta name="og:type" content="article" />
|
|
||||||
<Meta name="og:title" content={ogTitle} />
|
|
||||||
<Meta name="og:image" content={ogImage} />
|
|
||||||
<Meta name="og:description" content={description} />
|
|
||||||
<Meta name="twitter:card" content="summary_large_image" />
|
|
||||||
<Meta name="twitter:title" content={ogTitle} />
|
|
||||||
<Meta name="twitter:description" content={description} />
|
|
||||||
<Meta name="twitter:image" content={ogImage} />
|
|
||||||
|
|
||||||
<For each={imageUrls()}>{(imageUrl) => <Link rel="preload" as="image" href={imageUrl} />}</For>
|
<For each={imageUrls()}>{(imageUrl) => <Link rel="preload" as="image" href={imageUrl} />}</For>
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<div class="row position-relative">
|
<div class="row position-relative">
|
||||||
|
@ -382,9 +354,9 @@ export const FullArticle = (props: Props) => {
|
||||||
<CardTopic title={mainTopic()?.title || ''} slug={mainTopic()?.slug || ''} />
|
<CardTopic title={mainTopic()?.title || ''} slug={mainTopic()?.slug || ''} />
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<h1>{props.article.title}</h1>
|
<h1>{props.article.title || ''}</h1>
|
||||||
<Show when={props.article.subtitle}>
|
<Show when={props.article.subtitle}>
|
||||||
<h4>{props.article.subtitle}</h4>
|
<h4>{processPrepositions(props.article.subtitle || '')}</h4>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<div class={styles.shoutAuthor}>
|
<div class={styles.shoutAuthor}>
|
||||||
|
@ -392,7 +364,7 @@ export const FullArticle = (props: Props) => {
|
||||||
{(a: Maybe<Author>, index: () => number) => (
|
{(a: Maybe<Author>, index: () => number) => (
|
||||||
<>
|
<>
|
||||||
<Show when={index() > 0}>, </Show>
|
<Show when={index() > 0}>, </Show>
|
||||||
<A href={`/author/${a?.slug}`}>{a && getAuthorName(a)}</A>
|
<A href={`/@${a?.slug}`}>{a && getAuthorName(a)}</A>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
|
@ -416,18 +388,18 @@ export const FullArticle = (props: Props) => {
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={props.article.lead}>
|
<Show when={props.article.lead}>
|
||||||
<section class={styles.lead} innerHTML={props.article.lead || ''} />
|
<section class={styles.lead} innerHTML={processPrepositions(props.article.lead || '')} />
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={props.article.layout === 'audio'}>
|
<Show when={props.article.layout === 'audio'}>
|
||||||
<AudioHeader
|
<AudioHeader
|
||||||
title={props.article.title}
|
title={props.article.title || ''}
|
||||||
cover={props.article.cover || ''}
|
cover={props.article.cover || ''}
|
||||||
artistData={media()?.[0]}
|
artistData={media()?.[0]}
|
||||||
topic={mainTopic() as Topic}
|
topic={mainTopic() as Topic}
|
||||||
/>
|
/>
|
||||||
<Show when={media().length > 0}>
|
<Show when={media().length > 0}>
|
||||||
<div class="media-items">
|
<div class="media-items">
|
||||||
<AudioPlayer media={media()} articleSlug={props.article.slug} body={body()} />
|
<AudioPlayer media={media()} articleSlug={props.article.slug || ''} body={body()} />
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</Show>
|
</Show>
|
||||||
|
@ -539,9 +511,9 @@ export const FullArticle = (props: Props) => {
|
||||||
<div class={styles.shoutStatsItem} ref={triggerRef}>
|
<div class={styles.shoutStatsItem} ref={triggerRef}>
|
||||||
<SharePopup
|
<SharePopup
|
||||||
title={props.article.title}
|
title={props.article.title}
|
||||||
description={description}
|
description={props.article.description || body() || media()[0]?.body}
|
||||||
imageUrl={props.article.cover || ''}
|
imageUrl={props.article.cover || ''}
|
||||||
shareUrl={shareUrl}
|
shareUrl={shareUrl()}
|
||||||
containerCssClass={stylesHeader.control}
|
containerCssClass={stylesHeader.control}
|
||||||
onVisibilityChange={(isVisible) => setIsActionPopupActive(isVisible)}
|
onVisibilityChange={(isVisible) => setIsActionPopupActive(isVisible)}
|
||||||
trigger={
|
trigger={
|
||||||
|
@ -559,7 +531,7 @@ export const FullArticle = (props: Props) => {
|
||||||
<Popover content={t('Edit')}>
|
<Popover content={t('Edit')}>
|
||||||
{(triggerRef: (el: HTMLElement) => void) => (
|
{(triggerRef: (el: HTMLElement) => void) => (
|
||||||
<div class={styles.shoutStatsItem} ref={triggerRef}>
|
<div class={styles.shoutStatsItem} ref={triggerRef}>
|
||||||
<A href={`/edit/${props.article?.id}`} class={styles.shoutStatsItemInner}>
|
<A href={`/edit/${props.article.id}`} class={styles.shoutStatsItemInner}>
|
||||||
<Icon name="pencil-outline" class={styles.icon} />
|
<Icon name="pencil-outline" class={styles.icon} />
|
||||||
<Icon name="pencil-outline-hover" class={clsx(styles.icon, styles.iconHover)} />
|
<Icon name="pencil-outline-hover" class={clsx(styles.icon, styles.iconHover)} />
|
||||||
</A>
|
</A>
|
||||||
|
@ -596,7 +568,7 @@ export const FullArticle = (props: Props) => {
|
||||||
|
|
||||||
<Show when={props.article.topics?.length}>
|
<Show when={props.article.topics?.length}>
|
||||||
<div class={styles.topicsList}>
|
<div class={styles.topicsList}>
|
||||||
<For each={props.article.topics}>
|
<For each={props.article.topics || []}>
|
||||||
{(topic) => (
|
{(topic) => (
|
||||||
<div class={styles.shoutTopic}>
|
<div class={styles.shoutTopic}>
|
||||||
<A href={`/topic/${topic?.slug || ''}`}>
|
<A href={`/topic/${topic?.slug || ''}`}>
|
||||||
|
@ -640,9 +612,9 @@ export const FullArticle = (props: Props) => {
|
||||||
</Modal>
|
</Modal>
|
||||||
<ShareModal
|
<ShareModal
|
||||||
title={props.article.title}
|
title={props.article.title}
|
||||||
description={description}
|
description={props.article.description || body() || media()[0]?.body}
|
||||||
imageUrl={props.article.cover || ''}
|
imageUrl={props.article.cover || ''}
|
||||||
shareUrl={shareUrl}
|
shareUrl={shareUrl()}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useSearchParams } from '@solidjs/router'
|
import { useSearchParams } from '@solidjs/router'
|
||||||
import { JSX, Show, createEffect, createMemo, on } from 'solid-js'
|
import { JSX, Show, createEffect, createMemo, on } from 'solid-js'
|
||||||
|
import { useSession } from '~/context/session'
|
||||||
import { useUI } from '~/context/ui'
|
import { useUI } from '~/context/ui'
|
||||||
import { useSession } from '../../context/session'
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: JSX.Element
|
children: JSX.Element
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
.view {
|
.view {
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
min-height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
background: var(--background-color);
|
background: var(--background-color);
|
||||||
min-height: 550px;
|
min-height: 550px;
|
||||||
position: relative;
|
position: relative;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
|
||||||
min-height: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
input {
|
||||||
font-size: 1.7rem;
|
font-size: 1.7rem;
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,10 @@
|
||||||
.authImage {
|
.authImage {
|
||||||
@include font-size(1.5rem);
|
@include font-size(1.5rem);
|
||||||
|
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
background: var(--background-color-invert)
|
background: var(--background-color-invert)
|
||||||
url('https://images.discours.io/unsafe/1600x/production/image/auth-page.jpg') center no-repeat;
|
url('https://images.discours.io/unsafe/1600x/production/image/auth-page.jpg') center no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
|
@ -49,10 +53,6 @@
|
||||||
padding: 3em;
|
padding: 3em;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
@ -118,13 +118,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth {
|
.auth {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
padding: $container-padding-x;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(lg) {
|
@include media-breakpoint-up(lg) {
|
||||||
padding: 4rem !important;
|
padding: 4rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: $container-padding-x;
|
||||||
}
|
}
|
||||||
|
|
||||||
.submitButton {
|
.submitButton {
|
|
@ -1,6 +1,6 @@
|
||||||
import { useSearchParams } from '@solidjs/router'
|
import { useSearchParams } from '@solidjs/router'
|
||||||
import { Show } from 'solid-js'
|
import { Show } from 'solid-js'
|
||||||
import { useLocalize } from '../../../../context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import styles from './AuthModalHeader.module.scss'
|
import styles from './AuthModalHeader.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -14,7 +14,7 @@ export const AuthModalHeader = (props: Props) => {
|
||||||
const generateModalTextsFromSource = (
|
const generateModalTextsFromSource = (
|
||||||
modalType: 'login' | 'register'
|
modalType: 'login' | 'register'
|
||||||
): { title: string; description: string } => {
|
): { title: string; description: string } => {
|
||||||
const title = modalType === 'login' ? 'Welcome to Discours' : 'Create account'
|
const title = modalType === 'login' ? 'Welcome to Discours' : 'Sign up'
|
||||||
|
|
||||||
switch (searchParams?.source) {
|
switch (searchParams?.source) {
|
||||||
case 'create': {
|
case 'create': {
|
||||||
|
@ -27,7 +27,7 @@ export const AuthModalHeader = (props: Props) => {
|
||||||
return {
|
return {
|
||||||
title: t(`${title} to add to your bookmarks`),
|
title: t(`${title} to add to your bookmarks`),
|
||||||
description: t(
|
description: t(
|
||||||
'In bookmarks, you can save favorite discussions and materials that you want to return to'
|
'In bookmarks, you can save favorite discussions and materials that you want to return to'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ export const AuthModalHeader = (props: Props) => {
|
||||||
return {
|
return {
|
||||||
title: t(`${title} to participate in discussions`),
|
title: t(`${title} to participate in discussions`),
|
||||||
description: t(
|
description: t(
|
||||||
"You ll be able to participate in discussions, rate others' comments and learn about new responses"
|
"You ll be able to participate in discussions, rate others' comments and learn about new responses"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ export const AuthModalHeader = (props: Props) => {
|
||||||
return {
|
return {
|
||||||
title: t(`${title} to subscribe`),
|
title: t(`${title} to subscribe`),
|
||||||
description: t(
|
description: t(
|
||||||
'This way you ll be able to subscribe to authors, interesting topics and customize your feed'
|
'This way you ll be able to subscribe to authors, interesting topics and customize your feed'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ export const AuthModalHeader = (props: Props) => {
|
||||||
return {
|
return {
|
||||||
title: t(`${title} to subscribe to new publications`),
|
title: t(`${title} to subscribe to new publications`),
|
||||||
description: t(
|
description: t(
|
||||||
'This way you ll be able to subscribe to authors, interesting topics and customize your feed'
|
'This way you ll be able to subscribe to authors, interesting topics and customize your feed'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ export const AuthModalHeader = (props: Props) => {
|
||||||
return {
|
return {
|
||||||
title: t(`${title} to vote`),
|
title: t(`${title} to vote`),
|
||||||
description: t(
|
description: t(
|
||||||
'This way we ll realize that you re a real person and ll take your vote into account. And you ll see how others voted'
|
'This way we ll realize that you re a real person and ll take your vote into account. And you ll see how others voted'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { JSX, Show, createSignal } from 'solid-js'
|
import { JSX, Show, createSignal } from 'solid-js'
|
||||||
|
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
|
import { useSession } from '~/context/session'
|
||||||
import { useUI } from '~/context/ui'
|
import { useUI } from '~/context/ui'
|
||||||
import { useLocalize } from '../../../context/localize'
|
|
||||||
import { useSession } from '../../../context/session'
|
|
||||||
import { PasswordField } from './PasswordField'
|
import { PasswordField } from './PasswordField'
|
||||||
|
|
||||||
import { useSearchParams } from '@solidjs/router'
|
import { useSearchParams } from '@solidjs/router'
|
|
@ -1,9 +1,9 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Show, createEffect, createSignal } from 'solid-js'
|
import { Show, createEffect, createSignal } from 'solid-js'
|
||||||
|
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
|
import { useSession } from '~/context/session'
|
||||||
import { useUI } from '~/context/ui'
|
import { useUI } from '~/context/ui'
|
||||||
import { useLocalize } from '../../../context/localize'
|
|
||||||
import { useSession } from '../../../context/session'
|
|
||||||
|
|
||||||
import { email, setEmail } from './sharedLogic'
|
import { email, setEmail } from './sharedLogic'
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { JSX, Show, createSignal } from 'solid-js'
|
import { JSX, Show, createSignal } from 'solid-js'
|
||||||
|
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
|
import { useSession } from '~/context/session'
|
||||||
import { useSnackbar, useUI } from '~/context/ui'
|
import { useSnackbar, useUI } from '~/context/ui'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { validateEmail } from '~/utils/validate'
|
||||||
import { useSession } from '../../../context/session'
|
|
||||||
import { validateEmail } from '../../../utils/validateEmail'
|
|
||||||
|
|
||||||
import { AuthModalHeader } from './AuthModalHeader'
|
import { AuthModalHeader } from './AuthModalHeader'
|
||||||
import { PasswordField } from './PasswordField'
|
import { PasswordField } from './PasswordField'
|
|
@ -26,13 +26,13 @@
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
margin-top: 0.3em;
|
margin-top: 0.3em;
|
||||||
|
|
||||||
|
/* Red/500 */
|
||||||
|
color: orange;
|
||||||
|
|
||||||
&.registerPassword {
|
&.registerPassword {
|
||||||
margin-bottom: -32px;
|
margin-bottom: -32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Red/500 */
|
|
||||||
color: orange;
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: orange;
|
color: orange;
|
||||||
border-color: orange;
|
border-color: orange;
|
|
@ -1,9 +1,7 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Show, createEffect, createSignal, on } from 'solid-js'
|
import { Show, createEffect, createSignal, on } from 'solid-js'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useLocalize } from '../../../../context/localize'
|
import { Icon } from '../../_shared/Icon'
|
||||||
import { Icon } from '../../../_shared/Icon'
|
|
||||||
|
|
||||||
import styles from './PasswordField.module.scss'
|
import styles from './PasswordField.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
|
@ -3,10 +3,10 @@ import type { JSX } from 'solid-js'
|
||||||
import { Show, createMemo, createSignal } from 'solid-js'
|
import { Show, createMemo, createSignal } from 'solid-js'
|
||||||
|
|
||||||
import { useSearchParams } from '@solidjs/router'
|
import { useSearchParams } from '@solidjs/router'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
|
import { useSession } from '~/context/session'
|
||||||
import { useUI } from '~/context/ui'
|
import { useUI } from '~/context/ui'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { validateEmail } from '~/utils/validate'
|
||||||
import { useSession } from '../../../context/session'
|
|
||||||
import { validateEmail } from '../../../utils/validateEmail'
|
|
||||||
import { AuthModalHeader } from './AuthModalHeader'
|
import { AuthModalHeader } from './AuthModalHeader'
|
||||||
import { PasswordField } from './PasswordField'
|
import { PasswordField } from './PasswordField'
|
||||||
import { SocialProviders } from './SocialProviders'
|
import { SocialProviders } from './SocialProviders'
|
||||||
|
@ -134,7 +134,7 @@ export const RegisterForm = () => {
|
||||||
{t('This email is registered')}. {t('try')}
|
{t('This email is registered')}. {t('try')}
|
||||||
{', '}
|
{', '}
|
||||||
<span class="link" onClick={() => changeSearchParams({ mode: 'login' })}>
|
<span class="link" onClick={() => changeSearchParams({ mode: 'login' })}>
|
||||||
{t('enter')}
|
{t('Enter').toLocaleLowerCase()}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
|
@ -1,7 +1,7 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
|
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useUI } from '~/context/ui'
|
import { useUI } from '~/context/ui'
|
||||||
import { useLocalize } from '../../../context/localize'
|
|
||||||
|
|
||||||
import styles from './AuthModal.module.scss'
|
import styles from './AuthModal.module.scss'
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { JSX, Show, createSignal, onMount } from 'solid-js'
|
import { JSX, Show, createSignal, onMount } from 'solid-js'
|
||||||
|
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useSession } from '../../../context/session'
|
import { useSession } from '~/context/session'
|
||||||
import { validateEmail } from '../../../utils/validateEmail'
|
import { validateEmail } from '~/utils/validate'
|
||||||
import { email, setEmail } from './sharedLogic'
|
import { email, setEmail } from './sharedLogic'
|
||||||
|
|
||||||
import { useSearchParams } from '@solidjs/router'
|
import { useSearchParams } from '@solidjs/router'
|
|
@ -1,9 +1,7 @@
|
||||||
import { For } from 'solid-js'
|
import { For } from 'solid-js'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useLocalize } from '../../../../context/localize'
|
import { useSession } from '~/context/session'
|
||||||
import { useSession } from '../../../../context/session'
|
import { Icon } from '../../_shared/Icon'
|
||||||
import { Icon } from '../../../_shared/Icon'
|
|
||||||
|
|
||||||
import styles from './SocialProviders.module.scss'
|
import styles from './SocialProviders.module.scss'
|
||||||
|
|
||||||
export const PROVIDERS = ['facebook', 'google', 'github'] // 'vk' | 'telegram'
|
export const PROVIDERS = ['facebook', 'google', 'github'] // 'vk' | 'telegram'
|
|
@ -2,9 +2,9 @@ import { clsx } from 'clsx'
|
||||||
import { Component, Show, createEffect, createMemo } from 'solid-js'
|
import { Component, Show, createEffect, createMemo } from 'solid-js'
|
||||||
import { Dynamic } from 'solid-js/web'
|
import { Dynamic } from 'solid-js/web'
|
||||||
|
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { AuthModalSource, useUI } from '~/context/ui'
|
import { AuthModalSource, useUI } from '~/context/ui'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { isMobile } from '~/lib/mediaQuery'
|
||||||
import { isMobile } from '../../../utils/media-query'
|
|
||||||
import { ChangePasswordForm } from './ChangePasswordForm'
|
import { ChangePasswordForm } from './ChangePasswordForm'
|
||||||
import { EmailConfirm } from './EmailConfirm'
|
import { EmailConfirm } from './EmailConfirm'
|
||||||
import { LoginForm } from './LoginForm'
|
import { LoginForm } from './LoginForm'
|
||||||
|
@ -75,21 +75,20 @@ export const AuthModal = () => {
|
||||||
{t(
|
{t(
|
||||||
'Get to know the most intelligent people of our time, edit and discuss the articles, share your expertise, rate and decide what to publish in the magazine'
|
'Get to know the most intelligent people of our time, edit and discuss the articles, share your expertise, rate and decide what to publish in the magazine'
|
||||||
)}
|
)}
|
||||||
.
|
. {t('New stories and more are waiting for you every day!')}
|
||||||
{t('New stories every day and even more!')}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p class={styles.disclaimer}>
|
<p class={styles.disclaimer}>
|
||||||
{t('By signing up you agree with our')}{' '}
|
{t('By signing up you agree with our')}{' '}
|
||||||
<a
|
<a
|
||||||
href="/about/terms-of-use"
|
href="/terms"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
hideModal()
|
hideModal()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('terms of use')}
|
{t('terms of use')}
|
||||||
</a>
|
</a>
|
||||||
, {t('personal data usage and email notifications')}.
|
, {t('to process personal data and receive email notifications')}.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>{' '}
|
</div>{' '}
|
|
@ -1,4 +1,8 @@
|
||||||
.AuthorBadge {
|
.AuthorBadge {
|
||||||
|
@include media-breakpoint-down(md) {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
@ -12,34 +16,30 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.basicInfo {
|
.basicInfo {
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
flex: 0 100%;
|
||||||
|
}
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex: 0 calc(100% - 5.2rem);
|
flex: 0 calc(100% - 5.2rem);
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
|
||||||
flex: 0 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
@include font-size(1.4rem);
|
@include font-size(1.4rem);
|
||||||
|
|
||||||
|
@include media-breakpoint-up(sm) {
|
||||||
|
flex: 1 100%;
|
||||||
|
}
|
||||||
|
|
||||||
border: none;
|
border: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
|
||||||
flex: 1 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: unset;
|
background: unset;
|
||||||
}
|
}
|
||||||
|
@ -70,12 +70,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
flex: 0 20%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
margin-left: 5.2rem;
|
|
||||||
gap: 1rem;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
@include media-breakpoint-down(sm) {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
@ -90,6 +84,12 @@
|
||||||
padding-left: 1rem;
|
padding-left: 1rem;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flex: 0 20%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-left: 5.2rem;
|
||||||
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actionButton {
|
.actionButton {
|
||||||
|
|
|
@ -2,18 +2,18 @@ import { clsx } from 'clsx'
|
||||||
import { Match, Show, Switch, createEffect, createMemo, createSignal, on } from 'solid-js'
|
import { Match, Show, Switch, createEffect, createMemo, createSignal, on } from 'solid-js'
|
||||||
|
|
||||||
import { useNavigate, useSearchParams } from '@solidjs/router'
|
import { useNavigate, useSearchParams } from '@solidjs/router'
|
||||||
import { mediaMatches } from '~/utils/media-query'
|
import { Button } from '~/components/_shared/Button'
|
||||||
import { useFollowing } from '../../../context/following'
|
import { CheckButton } from '~/components/_shared/CheckButton'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { ConditionalWrapper } from '~/components/_shared/ConditionalWrapper'
|
||||||
import { useSession } from '../../../context/session'
|
import { FollowingButton } from '~/components/_shared/FollowingButton'
|
||||||
import { Author, FollowingEntity } from '../../../graphql/schema/core.gen'
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
import { translit } from '../../../utils/ru2en'
|
import { useFollowing } from '~/context/following'
|
||||||
import { isCyrillic } from '../../../utils/translate'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { Button } from '../../_shared/Button'
|
import { useSession } from '~/context/session'
|
||||||
import { CheckButton } from '../../_shared/CheckButton'
|
import { Author, FollowingEntity } from '~/graphql/schema/core.gen'
|
||||||
import { ConditionalWrapper } from '../../_shared/ConditionalWrapper'
|
import { isCyrillic } from '~/intl/translate'
|
||||||
import { FollowingButton } from '../../_shared/FollowingButton'
|
import { translit } from '~/intl/translit'
|
||||||
import { Icon } from '../../_shared/Icon'
|
import { mediaMatches } from '~/lib/mediaQuery'
|
||||||
import { Userpic } from '../Userpic'
|
import { Userpic } from '../Userpic'
|
||||||
import styles from './AuthorBadge.module.scss'
|
import styles from './AuthorBadge.module.scss'
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ export const AuthorBadge = (props: Props) => {
|
||||||
<ConditionalWrapper
|
<ConditionalWrapper
|
||||||
condition={!props.inviteView}
|
condition={!props.inviteView}
|
||||||
wrapper={(children) => (
|
wrapper={(children) => (
|
||||||
<a href={`/author/${props.author.slug}`} class={styles.info}>
|
<a href={`/@${props.author.slug}`} class={styles.info}>
|
||||||
{children}
|
{children}
|
||||||
</a>
|
</a>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,4 +1,16 @@
|
||||||
.author {
|
.author {
|
||||||
|
@include media-breakpoint-down(md) {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
margin-bottom: 2.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include media-breakpoint-down(lg) {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-flow: row nowrap;
|
flex-flow: row nowrap;
|
||||||
|
@ -8,14 +20,6 @@
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
|
||||||
margin-bottom: 2.4rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.authorName {
|
.authorName {
|
||||||
@include font-size(4rem);
|
@include font-size(4rem);
|
||||||
|
|
||||||
|
@ -32,15 +36,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.authorActions {
|
.authorActions {
|
||||||
|
@include media-breakpoint-down(md) {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
margin: 2rem -0.8rem 0 0;
|
margin: 2rem -0.8rem 0 0;
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.authorActionsLabel {
|
.authorActionsLabel {
|
||||||
|
@ -50,27 +54,24 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.authorActionsLabelMobile {
|
.authorActionsLabelMobile {
|
||||||
display: none;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
@include media-breakpoint-down(sm) {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.authorDetails {
|
.authorDetails {
|
||||||
display: block;
|
|
||||||
margin-bottom: 0;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(md) {
|
@include media-breakpoint-down(md) {
|
||||||
flex: 1 100%;
|
flex: 1 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.listWrapper & {
|
.listWrapper & {
|
||||||
align-items: flex-start;
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
@include media-breakpoint-down(sm) {
|
||||||
margin-bottom: 3rem;
|
margin-bottom: 3rem;
|
||||||
}
|
}
|
||||||
|
@ -79,6 +80,9 @@
|
||||||
margin-bottom: 3rem;
|
margin-bottom: 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
|
||||||
.circlewrap {
|
.circlewrap {
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
|
@ -88,10 +92,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-down(lg) {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonWriteMessage {
|
.buttonWriteMessage {
|
||||||
border-radius: 0.8rem;
|
border-radius: 0.8rem;
|
||||||
padding-bottom: 0.6rem;
|
padding-bottom: 0.6rem;
|
||||||
|
@ -100,8 +100,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.authorDetails {
|
.authorDetails {
|
||||||
flex: 0 0 auto;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
@include media-breakpoint-up(sm) {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -118,12 +116,11 @@
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.authorDetailsWrapper {
|
.authorDetailsWrapper {
|
||||||
flex: 1 0;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
@include media-breakpoint-up(sm) {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
@ -139,6 +136,9 @@
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
padding-right: 1.2rem;
|
padding-right: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flex: 1 0;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.authorName {
|
.authorName {
|
||||||
|
@ -160,6 +160,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.authorSubscribeSocial {
|
.authorSubscribeSocial {
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
flex: 1 100%;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include media-breakpoint-down(md) {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
margin: 0.5rem 0 2rem -0.4rem;
|
margin: 0.5rem 0 2rem -0.4rem;
|
||||||
|
@ -415,15 +424,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
|
||||||
flex: 1 100%;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:link {
|
a:link {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
@ -434,14 +434,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.subscribersContainer {
|
.subscribersContainer {
|
||||||
|
@include media-breakpoint-down(md) {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,22 @@
|
||||||
import type { Author, Community } from '../../../graphql/schema/core.gen'
|
import { redirect, useNavigate, useSearchParams } from '@solidjs/router'
|
||||||
|
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Show, createEffect, createMemo, createSignal, onMount } from 'solid-js'
|
import { For, Show, createEffect, createMemo, createSignal, onMount } from 'solid-js'
|
||||||
import { FollowsFilter, useFollowing } from '../../../context/following'
|
import { Button } from '~/components/_shared/Button'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import stylesButton from '~/components/_shared/Button/Button.module.scss'
|
||||||
import { useSession } from '../../../context/session'
|
import { FollowingCounters } from '~/components/_shared/FollowingCounters/FollowingCounters'
|
||||||
import { FollowingEntity, Topic } from '../../../graphql/schema/core.gen'
|
import { ShowOnlyOnClient } from '~/components/_shared/ShowOnlyOnClient'
|
||||||
import { isAuthor } from '../../../utils/isAuthor'
|
import { FollowsFilter, useFollowing } from '~/context/following'
|
||||||
import { translit } from '../../../utils/ru2en'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { isCyrillic } from '../../../utils/translate'
|
import { useSession } from '~/context/session'
|
||||||
|
import type { Author, Community } from '~/graphql/schema/core.gen'
|
||||||
|
import { FollowingEntity, Topic } from '~/graphql/schema/core.gen'
|
||||||
|
import { isCyrillic } from '~/intl/translate'
|
||||||
|
import { translit } from '~/intl/translit'
|
||||||
import { SharePopup, getShareUrl } from '../../Article/SharePopup'
|
import { SharePopup, getShareUrl } from '../../Article/SharePopup'
|
||||||
import { Modal } from '../../Nav/Modal'
|
|
||||||
import { TopicBadge } from '../../Topic/TopicBadge'
|
import { TopicBadge } from '../../Topic/TopicBadge'
|
||||||
import { Button } from '../../_shared/Button'
|
import { Modal } from '../../_shared/Modal'
|
||||||
import { FollowingCounters } from '../../_shared/FollowingCounters/FollowingCounters'
|
|
||||||
import { ShowOnlyOnClient } from '../../_shared/ShowOnlyOnClient'
|
|
||||||
import { AuthorBadge } from '../AuthorBadge'
|
import { AuthorBadge } from '../AuthorBadge'
|
||||||
import { Userpic } from '../Userpic'
|
import { Userpic } from '../Userpic'
|
||||||
|
|
||||||
import { useNavigate, useSearchParams } from '@solidjs/router'
|
|
||||||
import stylesButton from '../../_shared/Button/Button.module.scss'
|
|
||||||
import styles from './AuthorCard.module.scss'
|
import styles from './AuthorCard.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -164,10 +161,10 @@ export const AuthorCard = (props: Props) => {
|
||||||
<div class="col-24">
|
<div class="col-24">
|
||||||
<For each={authorSubs()}>
|
<For each={authorSubs()}>
|
||||||
{(subscription) =>
|
{(subscription) =>
|
||||||
isAuthor(subscription) ? (
|
'name' in subscription ? (
|
||||||
<AuthorBadge author={subscription} subscriptionsMode={true} />
|
<AuthorBadge author={subscription as Author} subscriptionsMode={true} />
|
||||||
) : (
|
) : (
|
||||||
<TopicBadge topic={subscription} subscriptionsMode={true} />
|
<TopicBadge topic={subscription as Topic} subscriptionsMode={true} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</For>
|
</For>
|
||||||
|
@ -252,7 +249,7 @@ export const AuthorCard = (props: Props) => {
|
||||||
<div class={styles.authorActions}>
|
<div class={styles.authorActions}>
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() => navigate('/profile/settings')}
|
onClick={() => redirect('/profile')}
|
||||||
value={
|
value={
|
||||||
<>
|
<>
|
||||||
<span class={styles.authorActionsLabel}>{t('Edit profile')}</span>
|
<span class={styles.authorActionsLabel}>{t('Edit profile')}</span>
|
||||||
|
@ -265,7 +262,7 @@ export const AuthorCard = (props: Props) => {
|
||||||
description={props.author.bio || ''}
|
description={props.author.bio || ''}
|
||||||
imageUrl={props.author.pic || ''}
|
imageUrl={props.author.pic || ''}
|
||||||
shareUrl={getShareUrl({
|
shareUrl={getShareUrl({
|
||||||
pathname: `/author/${props.author.slug}`
|
pathname: `/@${props.author.slug}`
|
||||||
})}
|
})}
|
||||||
trigger={<Button variant="secondary" value={t('Share')} />}
|
trigger={<Button variant="secondary" value={t('Share')} />}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { createMemo } from 'solid-js'
|
import { createMemo } from 'solid-js'
|
||||||
|
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { Author } from '../../../graphql/schema/core.gen'
|
import { Author } from '~/graphql/schema/core.gen'
|
||||||
import { capitalize } from '../../../utils/capitalize'
|
import { isCyrillic } from '~/intl/translate'
|
||||||
import { translit } from '../../../utils/ru2en'
|
import { translit } from '~/intl/translit'
|
||||||
import { isCyrillic } from '../../../utils/translate'
|
import { capitalize } from '~/utils/capitalize'
|
||||||
import { Userpic } from '../Userpic'
|
import { Userpic } from '../Userpic'
|
||||||
|
|
||||||
import styles from './AhtorLink.module.scss'
|
import styles from './AhtorLink.module.scss'
|
||||||
|
@ -30,7 +30,7 @@ export const AuthorLink = (props: Props) => {
|
||||||
[styles.authorLinkFloorImportant]: props.isFloorImportant
|
[styles.authorLinkFloorImportant]: props.isFloorImportant
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<a class={styles.link} href={`/author/${props.author.slug}`}>
|
<a class={styles.link} href={`/@${props.author.slug}`}>
|
||||||
<Userpic size={props.size ?? 'M'} name={name() || ''} userpic={props.author.pic || ''} />
|
<Userpic size={props.size ?? 'M'} name={name() || ''} userpic={props.author.pic || ''} />
|
||||||
<div class={styles.name}>{name()}</div>
|
<div class={styles.name}>{name()}</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Author } from '../../graphql/schema/core.gen'
|
import type { Author } from '~/graphql/schema/core.gen'
|
||||||
|
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Show, createSignal } from 'solid-js'
|
import { Show, createSignal } from 'solid-js'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Author } from '../../graphql/schema/core.gen'
|
import type { Author } from '~/graphql/schema/core.gen'
|
||||||
|
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { createMemo } from 'solid-js'
|
import { createMemo } from 'solid-js'
|
||||||
|
|
|
@ -86,17 +86,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.XL {
|
&.XL {
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
margin: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
aspect-ratio: 1/1;
|
aspect-ratio: 1/1;
|
||||||
margin: 0 auto 1rem;
|
margin: 0 auto 1rem;
|
||||||
max-width: 168px;
|
max-width: 168px;
|
||||||
height: auto;
|
height: auto;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
|
||||||
margin: 0;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.letters {
|
.letters {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Show, createMemo } from 'solid-js'
|
import { Show, createMemo } from 'solid-js'
|
||||||
|
|
||||||
import { ConditionalWrapper } from '../../_shared/ConditionalWrapper'
|
import { ConditionalWrapper } from '~/components/_shared/ConditionalWrapper'
|
||||||
import { Image } from '../../_shared/Image'
|
import { Image } from '~/components/_shared/Image'
|
||||||
import { Loading } from '../../_shared/Loading'
|
import { Loading } from '~/components/_shared/Loading'
|
||||||
|
|
||||||
import styles from './Userpic.module.scss'
|
import styles from './Userpic.module.scss'
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ export const Userpic = (props: Props) => {
|
||||||
<Show when={!props.loading} fallback={<Loading />}>
|
<Show when={!props.loading} fallback={<Loading />}>
|
||||||
<ConditionalWrapper
|
<ConditionalWrapper
|
||||||
condition={Boolean(props.hasLink)}
|
condition={Boolean(props.hasLink)}
|
||||||
wrapper={(children) => <a href={`/author/${props.slug}`}>{children}</a>}
|
wrapper={(children) => <a href={`/@${props.slug}`}>{children}</a>}
|
||||||
>
|
>
|
||||||
<Show keyed={true} when={props.userpic} fallback={<div class={styles.letters}>{letters()}</div>}>
|
<Show keyed={true} when={props.userpic} fallback={<div class={styles.letters}>{letters()}</div>}>
|
||||||
<Image src={props.userpic} width={avatarSize()} height={avatarSize()} alt={props.name} />
|
<Image src={props.userpic} width={avatarSize()} height={avatarSize()} alt={props.name} />
|
||||||
|
|
|
@ -1,110 +0,0 @@
|
||||||
import { clsx } from 'clsx'
|
|
||||||
import { For, Show, createEffect, createSignal, on } from 'solid-js'
|
|
||||||
import { useAuthors } from '~/context/authors'
|
|
||||||
import { useGraphQL } from '~/context/graphql'
|
|
||||||
import loadAuthorsByQuery from '~/graphql/query/core/authors-load-by'
|
|
||||||
import { Author } from '~/graphql/schema/core.gen'
|
|
||||||
import { useLocalize } from '../../context/localize'
|
|
||||||
import { AuthorBadge } from '../Author/AuthorBadge'
|
|
||||||
import { InlineLoader } from '../InlineLoader'
|
|
||||||
import { Button } from '../_shared/Button'
|
|
||||||
import styles from './AuthorsList.module.scss'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
class?: string
|
|
||||||
query: 'followers' | 'shouts'
|
|
||||||
searchQuery?: string
|
|
||||||
allAuthorsLength?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
const PAGE_SIZE = 20
|
|
||||||
|
|
||||||
export const AuthorsList = (props: Props) => {
|
|
||||||
const { t } = useLocalize()
|
|
||||||
const { addAuthors } = useAuthors()
|
|
||||||
const [authorsByShouts, setAuthorsByShouts] = createSignal<Author[]>()
|
|
||||||
const [authorsByFollowers, setAuthorsByFollowers] = createSignal<Author[]>()
|
|
||||||
const [loading, setLoading] = createSignal(false)
|
|
||||||
const [currentPage, setCurrentPage] = createSignal({ shouts: 0, followers: 0 })
|
|
||||||
const [allLoaded, setAllLoaded] = createSignal(false)
|
|
||||||
const { query } = useGraphQL()
|
|
||||||
|
|
||||||
const fetchAuthors = async (queryType: Props['query'], page: number) => {
|
|
||||||
setLoading(true)
|
|
||||||
const offset = PAGE_SIZE * page
|
|
||||||
const resp = await query(loadAuthorsByQuery, {
|
|
||||||
by: { order: queryType },
|
|
||||||
limit: PAGE_SIZE,
|
|
||||||
offset
|
|
||||||
})
|
|
||||||
const result = resp?.data?.load_authors_by
|
|
||||||
if ((result?.length || 0) > 0) {
|
|
||||||
addAuthors([...result])
|
|
||||||
if (queryType === 'shouts') {
|
|
||||||
setAuthorsByShouts((prev) => [...(prev || []), ...result])
|
|
||||||
} else if (queryType === 'followers') {
|
|
||||||
setAuthorsByFollowers((prev) => [...(prev || []), ...result])
|
|
||||||
}
|
|
||||||
setLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadMoreAuthors = () => {
|
|
||||||
const nextPage = currentPage()[props.query] + 1
|
|
||||||
fetchAuthors(props.query, nextPage).then(() =>
|
|
||||||
setCurrentPage({ ...currentPage(), [props.query]: nextPage })
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
createEffect(
|
|
||||||
on(
|
|
||||||
() => props.query,
|
|
||||||
(query) => {
|
|
||||||
const al = query === 'shouts' ? authorsByShouts() : authorsByFollowers()
|
|
||||||
if (al?.length === 0 && currentPage()[query] === 0) {
|
|
||||||
setCurrentPage((prev) => ({ ...prev, [query]: 0 }))
|
|
||||||
fetchAuthors(query, 0).then(() => setCurrentPage((prev) => ({ ...prev, [query]: 1 })))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
const authorsList = () => (props.query === 'shouts' ? authorsByShouts() : authorsByFollowers())
|
|
||||||
|
|
||||||
// TODO: do it with backend
|
|
||||||
// createEffect(() => {
|
|
||||||
// if (props.searchQuery) {
|
|
||||||
// // search logic
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
setAllLoaded(props.allAuthorsLength === authorsList.length)
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div class={clsx(styles.AuthorsList, props.class)}>
|
|
||||||
<For each={authorsList()}>
|
|
||||||
{(author) => (
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-20 col-xl-18">
|
|
||||||
<AuthorBadge author={author} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-20 col-xl-18">
|
|
||||||
<div class={styles.action}>
|
|
||||||
<Show when={!loading() && (authorsList()?.length || 0) > 0 && !allLoaded()}>
|
|
||||||
<Button value={t('Load more')} onClick={loadMoreAuthors} />
|
|
||||||
</Show>
|
|
||||||
<Show when={loading() && !allLoaded()}>
|
|
||||||
<InlineLoader />
|
|
||||||
</Show>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export { AuthorsList } from './AuthorsList'
|
|
|
@ -1,12 +1,12 @@
|
||||||
.discoursBanner {
|
.discoursBanner {
|
||||||
background: #f8f8f8;
|
|
||||||
margin-bottom: 6.4rem;
|
|
||||||
padding: 0.8rem 0 0;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
@include media-breakpoint-down(sm) {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
background: #f8f8f8;
|
||||||
|
margin-bottom: 6.4rem;
|
||||||
|
padding: 0.8rem 0 0;
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
font-size: 3.2rem;
|
font-size: 3.2rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
|
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useUI } from '~/context/ui'
|
import { useUI } from '~/context/ui'
|
||||||
import { useLocalize } from '../../context/localize'
|
|
||||||
import { Image } from '../_shared/Image'
|
import { Image } from '../_shared/Image'
|
||||||
|
|
||||||
import styles from './Banner.module.scss'
|
import styles from './Banner.module.scss'
|
||||||
|
@ -14,10 +14,10 @@ export default () => {
|
||||||
<div class="wide-container">
|
<div class="wide-container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class={clsx(styles.discoursBannerContent, 'col-lg-10')}>
|
<div class={clsx(styles.discoursBannerContent, 'col-lg-10')}>
|
||||||
<h3>{t('Discours is created with our common effort')}</h3>
|
<h3>{t('Discours exists because of our common effort')}</h3>
|
||||||
<p>
|
<p>
|
||||||
<a href="/about/help">{t('Support us')}</a>
|
<a href="/support">{t('Support us')}</a>
|
||||||
<a href="/create">{t('Become an author')}</a>
|
<a href="/edit/new">{t('Become an author')}</a>
|
||||||
<a href={''} onClick={() => showModal('auth')}>
|
<a href={''} onClick={() => showModal('auth')}>
|
||||||
{t('Join the community')}
|
{t('Join the community')}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -24,12 +24,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
|
box-shadow: inset 0 0 0 3px #000;
|
||||||
|
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.2s ease;
|
transition: opacity 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
box-shadow: inset 0 0 0 3px #000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:valid,
|
&:valid,
|
||||||
|
@ -49,18 +49,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.donateForm .btn {
|
.donateForm .btn {
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
&:last-of-type {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
transform: none !important;
|
transform: none !important;
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
|
||||||
&:last-of-type {
|
|
||||||
margin-right: 0 !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btnGroup {
|
.btnGroup {
|
||||||
|
@ -82,22 +82,22 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.donateButtonsContainer {
|
.donateButtonsContainer {
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
input,
|
||||||
label {
|
label {
|
||||||
margin: 0 8px;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
@include media-breakpoint-down(sm) {
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
margin: 0 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { createSignal, onMount } from 'solid-js'
|
import { createSignal, onMount } from 'solid-js'
|
||||||
|
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useSnackbar, useUI } from '~/context/ui'
|
import { useSnackbar, useUI } from '~/context/ui'
|
||||||
import { useLocalize } from '../../context/localize'
|
|
||||||
|
|
||||||
import styles from './Donate.module.scss'
|
import styles from './Donate.module.scss'
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useUI } from '~/context/ui'
|
import { useUI } from '~/context/ui'
|
||||||
import { useLocalize } from '../../context/localize'
|
|
||||||
import { Button } from '../_shared/Button'
|
import { Button } from '../_shared/Button'
|
||||||
|
|
||||||
export const Feedback = () => {
|
export const Feedback = () => {
|
||||||
|
|
|
@ -88,16 +88,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.socialItem {
|
.socialItem {
|
||||||
margin-top: 1em;
|
|
||||||
text-align: center;
|
|
||||||
width: 25%;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-left: 0.3em;
|
margin-left: 0.3em;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
margin-top: 1em;
|
||||||
|
text-align: center;
|
||||||
|
width: 25%;
|
||||||
|
|
||||||
a:link {
|
a:link {
|
||||||
border: none;
|
border: none;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, createSignal, onMount } from 'solid-js'
|
import { For, createSignal, onMount } from 'solid-js'
|
||||||
import { useLocalize } from '../../context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { Icon } from '../_shared/Icon'
|
import { Icon } from '../_shared/Icon'
|
||||||
import { Newsletter } from '../_shared/Newsletter'
|
import { Newsletter } from '../_shared/Newsletter'
|
||||||
import styles from './Footer.module.scss'
|
import styles from './Footer.module.scss'
|
||||||
|
@ -25,10 +25,10 @@ export const FooterView = () => {
|
||||||
{
|
{
|
||||||
header: t('About the project'),
|
header: t('About the project'),
|
||||||
items: [
|
items: [
|
||||||
{ title: t('Discours Manifest'), slug: '/about/manifest' },
|
{ title: t('Discours Manifest'), slug: '/manifest' },
|
||||||
{ title: t('How it works'), slug: '/about/guide' },
|
{ title: t('How it works'), slug: '/guide' },
|
||||||
{ title: t('Dogma'), slug: '/about/dogma' },
|
{ title: t('Dogma'), slug: '/dogma' },
|
||||||
{ title: t('Principles'), slug: '/about/principles' },
|
{ title: t('Our principles'), slug: '/principles' },
|
||||||
{ title: t('How to write an article'), slug: '/how-to-write-a-good-article' }
|
{ title: t('How to write an article'), slug: '/how-to-write-a-good-article' }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -36,10 +36,10 @@ export const FooterView = () => {
|
||||||
header: t('Participating'),
|
header: t('Participating'),
|
||||||
items: [
|
items: [
|
||||||
{ title: t('Suggest an idea'), slug: '/connect' },
|
{ title: t('Suggest an idea'), slug: '/connect' },
|
||||||
{ title: t('Become an author'), slug: '/create' },
|
{ title: t('Become an author'), slug: '/edit/new' },
|
||||||
{ title: t('Support Discours'), slug: '/about/help' },
|
{ title: t('Support Discours'), slug: '/support' },
|
||||||
{
|
{
|
||||||
title: t('Work with us'),
|
title: t('Cooperate with Discours'),
|
||||||
slug: 'https://docs.google.com/forms/d/e/1FAIpQLSeNNvIzKlXElJtkPkYiXl-jQjlvsL9u4-kpnoRjz1O8Wo40xQ/viewform'
|
slug: 'https://docs.google.com/forms/d/e/1FAIpQLSeNNvIzKlXElJtkPkYiXl-jQjlvsL9u4-kpnoRjz1O8Wo40xQ/viewform'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -47,10 +47,10 @@ export const FooterView = () => {
|
||||||
{
|
{
|
||||||
header: t('Sections'),
|
header: t('Sections'),
|
||||||
items: [
|
items: [
|
||||||
{ title: t('Authors'), slug: '/authors' },
|
{ title: t('Authors'), slug: '/author' },
|
||||||
{ title: t('Communities'), slug: '/community' },
|
{ title: t('Communities'), slug: '/community' },
|
||||||
{ title: t('Partners'), slug: '/about/partners' },
|
{ title: t('Partners'), slug: '/partners' },
|
||||||
{ title: t('Special projects'), slug: '/about/projects' },
|
{ title: t('Special projects'), slug: '/projects' },
|
||||||
{
|
{
|
||||||
title: lang() === 'ru' ? 'English' : 'Русский',
|
title: lang() === 'ru' ? 'English' : 'Русский',
|
||||||
slug: `?lng=${lang() === 'ru' ? 'en' : 'ru'}`,
|
slug: `?lng=${lang() === 'ru' ? 'en' : 'ru'}`,
|
||||||
|
@ -97,7 +97,7 @@ export const FooterView = () => {
|
||||||
'Independant magazine with an open horizontal cooperation about culture, science and society'
|
'Independant magazine with an open horizontal cooperation about culture, science and society'
|
||||||
)}
|
)}
|
||||||
. {t('Discours')} © 2015–{new Date().getFullYear()}{' '}
|
. {t('Discours')} © 2015–{new Date().getFullYear()}{' '}
|
||||||
<a href="/about/terms-of-use">{t('Terms of use')}</a>
|
<a href="/terms">{t('Terms of use')}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class={clsx(styles.footerCopyrightSocial, 'col-md-6 col-lg-4')}>
|
<div class={clsx(styles.footerCopyrightSocial, 'col-md-6 col-lg-4')}>
|
||||||
<For each={social}>
|
<For each={social}>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useUI } from '~/context/ui'
|
import { useUI } from '~/context/ui'
|
||||||
import { useLocalize } from '../../context/localize'
|
|
||||||
|
|
||||||
import { useSearchParams } from '@solidjs/router'
|
import { useSearchParams } from '@solidjs/router'
|
||||||
import styles from './Hero.module.scss'
|
import styles from './Hero.module.scss'
|
||||||
|
@ -20,7 +20,7 @@ export default () => {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<div class={styles.aboutDiscoursActions}>
|
<div class={styles.aboutDiscoursActions}>
|
||||||
<a class="button" href="/create">
|
<a class="button" href="/edit/new">
|
||||||
{t('Create post')}
|
{t('Create post')}
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
|
@ -34,7 +34,7 @@ export default () => {
|
||||||
>
|
>
|
||||||
{t('Join the community')}
|
{t('Join the community')}
|
||||||
</a>
|
</a>
|
||||||
<a class="button" href="/about/help">
|
<a class="button" href="/support">
|
||||||
{t('Support us')}
|
{t('Support us')}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
|
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useSnackbar, useUI } from '~/context/ui'
|
import { useSnackbar, useUI } from '~/context/ui'
|
||||||
import { useLocalize } from '../../context/localize'
|
import type { Shout } from '~/graphql/schema/core.gen'
|
||||||
import type { Shout } from '../../graphql/schema/core.gen'
|
|
||||||
import { Icon } from '../_shared/Icon'
|
import { Icon } from '../_shared/Icon'
|
||||||
|
|
||||||
import { A } from '@solidjs/router'
|
import { A } from '@solidjs/router'
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Show } from 'solid-js'
|
import { Show } from 'solid-js'
|
||||||
|
import { isServer } from 'solid-js/web'
|
||||||
|
import { DropArea } from '~/components/_shared/DropArea'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
|
import { composeMediaItems } from '~/lib/composeMediaItems'
|
||||||
import { MediaItem } from '~/types/mediaitem'
|
import { MediaItem } from '~/types/mediaitem'
|
||||||
import { useLocalize } from '../../../context/localize'
|
|
||||||
import { composeMediaItems } from '../../../utils/composeMediaItems'
|
|
||||||
import { AudioPlayer } from '../../Article/AudioPlayer'
|
import { AudioPlayer } from '../../Article/AudioPlayer'
|
||||||
import { DropArea } from '../../_shared/DropArea'
|
|
||||||
|
|
||||||
// import { Buffer } from 'node:buffer'
|
|
||||||
import styles from './AudioUploader.module.scss'
|
import styles from './AudioUploader.module.scss'
|
||||||
|
|
||||||
if (window) window.Buffer = Buffer
|
if (!isServer && window) window.Buffer = Buffer
|
||||||
|
// console.debug('buffer patch passed')
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
class?: string
|
class?: string
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
|
import { Loading } from '~/components/_shared/Loading'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { Loading } from '../../_shared/Loading'
|
|
||||||
|
|
||||||
import styles from './AutoSaveNotice.module.scss'
|
import styles from './AutoSaveNotice.module.scss'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import type { Editor } from '@tiptap/core'
|
import type { Editor } from '@tiptap/core'
|
||||||
|
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
import { Icon } from '../../_shared/Icon'
|
import { Popover } from '~/components/_shared/Popover'
|
||||||
import { Popover } from '../../_shared/Popover'
|
import { useLocalize } from '~/context/localize'
|
||||||
|
|
||||||
import styles from './BubbleMenu.module.scss'
|
import styles from './BubbleMenu.module.scss'
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import type { Editor } from '@tiptap/core'
|
import type { Editor } from '@tiptap/core'
|
||||||
|
|
||||||
|
import { renderUploadedImage } from '~/components/Editor/renderUploadedImage'
|
||||||
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
|
import { Popover } from '~/components/_shared/Popover'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { UploadedFile } from '~/types/upload'
|
import { UploadedFile } from '~/types/upload'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { Modal } from '../../_shared/Modal'
|
||||||
import { renderUploadedImage } from '../../../utils/renderUploadedImage'
|
|
||||||
import { Modal } from '../../Nav/Modal'
|
|
||||||
import { Icon } from '../../_shared/Icon'
|
|
||||||
import { Popover } from '../../_shared/Popover'
|
|
||||||
import { UploadModalContent } from '../UploadModalContent'
|
import { UploadModalContent } from '../UploadModalContent'
|
||||||
|
|
||||||
import { useUI } from '~/context/ui'
|
import { useUI } from '~/context/ui'
|
||||||
|
|
|
@ -3,8 +3,8 @@ import type { Editor } from '@tiptap/core'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Show, createSignal } from 'solid-js'
|
import { For, Show, createSignal } from 'solid-js'
|
||||||
|
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
import { Icon } from '../../_shared/Icon'
|
import { useLocalize } from '~/context/localize'
|
||||||
|
|
||||||
import styles from './BubbleMenu.module.scss'
|
import styles from './BubbleMenu.module.scss'
|
||||||
|
|
||||||
|
|
|
@ -30,11 +30,11 @@ import { createTiptapEditor, useEditorHTML } from 'solid-tiptap'
|
||||||
import uniqolor from 'uniqolor'
|
import uniqolor from 'uniqolor'
|
||||||
import { Doc } from 'yjs'
|
import { Doc } from 'yjs'
|
||||||
|
|
||||||
|
import { useEditorContext } from '~/context/editor'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
|
import { useSession } from '~/context/session'
|
||||||
import { useSnackbar } from '~/context/ui'
|
import { useSnackbar } from '~/context/ui'
|
||||||
import { useEditorContext } from '../../context/editor'
|
import { handleImageUpload } from '~/lib/handleImageUpload'
|
||||||
import { useLocalize } from '../../context/localize'
|
|
||||||
import { useSession } from '../../context/session'
|
|
||||||
import { handleImageUpload } from '../../utils/handleImageUpload'
|
|
||||||
|
|
||||||
import { BlockquoteBubbleMenu, FigureBubbleMenu, IncutBubbleMenu } from './BubbleMenu'
|
import { BlockquoteBubbleMenu, FigureBubbleMenu, IncutBubbleMenu } from './BubbleMenu'
|
||||||
import { EditorFloatingMenu } from './EditorFloatingMenu'
|
import { EditorFloatingMenu } from './EditorFloatingMenu'
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import type { Editor } from '@tiptap/core'
|
import type { Editor } from '@tiptap/core'
|
||||||
import { Show, createEffect, createSignal } from 'solid-js'
|
import { Show, createEffect, createSignal } from 'solid-js'
|
||||||
|
|
||||||
|
import { renderUploadedImage } from '~/components/Editor/renderUploadedImage'
|
||||||
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useUI } from '~/context/ui'
|
import { useUI } from '~/context/ui'
|
||||||
|
import { useOutsideClickHandler } from '~/lib/useOutsideClickHandler'
|
||||||
import { UploadedFile } from '~/types/upload'
|
import { UploadedFile } from '~/types/upload'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { Modal } from '../../_shared/Modal'
|
||||||
import { renderUploadedImage } from '../../../utils/renderUploadedImage'
|
|
||||||
import { useOutsideClickHandler } from '../../../utils/useOutsideClickHandler'
|
|
||||||
import { Modal } from '../../Nav/Modal'
|
|
||||||
import { Icon } from '../../_shared/Icon'
|
|
||||||
import { InlineForm } from '../InlineForm'
|
import { InlineForm } from '../InlineForm'
|
||||||
import { UploadModalContent } from '../UploadModalContent'
|
import { UploadModalContent } from '../UploadModalContent'
|
||||||
import { Menu } from './Menu'
|
import { Menu } from './Menu'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useLocalize } from '../../../../context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { Icon } from '../../../_shared/Icon'
|
import { Icon } from '../../../_shared/Icon'
|
||||||
import { Popover } from '../../../_shared/Popover'
|
import { Popover } from '../../../_shared/Popover'
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { createSignal, onMount } from 'solid-js'
|
import { createSignal, onMount } from 'solid-js'
|
||||||
|
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
import { Icon } from '../../_shared/Icon'
|
import { Popover } from '~/components/_shared/Popover'
|
||||||
import { Popover } from '../../_shared/Popover'
|
import { useLocalize } from '~/context/localize'
|
||||||
|
|
||||||
import styles from './InlineForm.module.scss'
|
import styles from './InlineForm.module.scss'
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { Editor } from '@tiptap/core'
|
import { Editor } from '@tiptap/core'
|
||||||
import { createEditorTransaction } from 'solid-tiptap'
|
import { createEditorTransaction } from 'solid-tiptap'
|
||||||
|
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { validateUrl } from '../../../utils/validateUrl'
|
import { validateUrl } from '~/utils/validate'
|
||||||
import { InlineForm } from '../InlineForm'
|
import { InlineForm } from '../InlineForm'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
|
import { A } from '@solidjs/router'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Show, createSignal } from 'solid-js'
|
import { Show, createSignal } from 'solid-js'
|
||||||
import { useEditorHTML } from 'solid-tiptap'
|
import { useEditorHTML } from 'solid-tiptap'
|
||||||
import Typograf from 'typograf'
|
import Typograf from 'typograf'
|
||||||
|
import { Button } from '~/components/_shared/Button'
|
||||||
|
import { DarkModeToggle } from '~/components/_shared/DarkModeToggle'
|
||||||
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
|
import { useEditorContext } from '~/context/editor'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useUI } from '~/context/ui'
|
import { useUI } from '~/context/ui'
|
||||||
import { useEditorContext } from '../../../context/editor'
|
import { useEscKeyDownHandler } from '~/lib/useEscKeyDownHandler'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { useOutsideClickHandler } from '~/lib/useOutsideClickHandler'
|
||||||
import { useEscKeyDownHandler } from '../../../utils/useEscKeyDownHandler'
|
|
||||||
import { useOutsideClickHandler } from '../../../utils/useOutsideClickHandler'
|
|
||||||
import { Button } from '../../_shared/Button'
|
|
||||||
import { DarkModeToggle } from '../../_shared/DarkModeToggle'
|
|
||||||
import { Icon } from '../../_shared/Icon'
|
|
||||||
|
|
||||||
import { A } from '@solidjs/router'
|
|
||||||
import styles from './Panel.module.scss'
|
import styles from './Panel.module.scss'
|
||||||
|
|
||||||
const typograf = new Typograf({ locale: ['ru', 'en-US'] })
|
const typograf = new Typograf({ locale: ['ru', 'en-US'] })
|
||||||
|
@ -164,27 +162,27 @@ export const Panel = (props: Props) => {
|
||||||
<div class={clsx(styles.actionsHolder, styles.scrolled, { hidden: !isShortcutsVisible() })}>
|
<div class={clsx(styles.actionsHolder, styles.scrolled, { hidden: !isShortcutsVisible() })}>
|
||||||
<p>
|
<p>
|
||||||
<button class={styles.backToMenuControl} onClick={() => setIsShortcutsVisible(false)}>
|
<button class={styles.backToMenuControl} onClick={() => setIsShortcutsVisible(false)}>
|
||||||
{t('back to menu"')}
|
{t('Back to menu"').toLocaleLowerCase()}
|
||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<section class={styles.shortcutList}>
|
<section class={styles.shortcutList}>
|
||||||
<p>
|
<p>
|
||||||
{t('bold')}
|
{t('Bold').toLocaleLowerCase()}
|
||||||
<span class={styles.shortcut}>
|
<span class={styles.shortcut}>
|
||||||
<span class={styles.shortcutButton}>Ctrl</span>
|
<span class={styles.shortcutButton}>Ctrl</span>
|
||||||
<span class={styles.shortcutButton}>B</span>
|
<span class={styles.shortcutButton}>B</span>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{t('italic')}
|
{t('Italic').toLocaleLowerCase()}
|
||||||
<span class={styles.shortcut}>
|
<span class={styles.shortcut}>
|
||||||
<span class={styles.shortcutButton}>Ctrl</span>
|
<span class={styles.shortcutButton}>Ctrl</span>
|
||||||
<span class={styles.shortcutButton}>I</span>
|
<span class={styles.shortcutButton}>I</span>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{t('add link')}
|
{t('Add link').toLocaleLowerCase()}
|
||||||
<span class={styles.shortcut}>
|
<span class={styles.shortcut}>
|
||||||
<span class={styles.shortcutButton}>Ctrl</span>
|
<span class={styles.shortcutButton}>Ctrl</span>
|
||||||
<span class={styles.shortcutButton}>K</span>
|
<span class={styles.shortcutButton}>K</span>
|
||||||
|
@ -194,7 +192,7 @@ export const Panel = (props: Props) => {
|
||||||
|
|
||||||
<section class={styles.shortcutList}>
|
<section class={styles.shortcutList}>
|
||||||
<p>
|
<p>
|
||||||
{t('header 1')}
|
{t('Header 1').toLocaleLowerCase()}
|
||||||
<span class={styles.shortcut}>
|
<span class={styles.shortcut}>
|
||||||
<span class={styles.shortcutButton}>Ctrl</span>
|
<span class={styles.shortcutButton}>Ctrl</span>
|
||||||
<span class={styles.shortcutButton}>Alt</span>
|
<span class={styles.shortcutButton}>Alt</span>
|
||||||
|
@ -202,7 +200,7 @@ export const Panel = (props: Props) => {
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{t('header 2')}
|
{t('Header 2').toLocaleLowerCase()}
|
||||||
<span class={styles.shortcut}>
|
<span class={styles.shortcut}>
|
||||||
<span class={styles.shortcutButton}>Ctrl</span>
|
<span class={styles.shortcutButton}>Ctrl</span>
|
||||||
<span class={styles.shortcutButton}>Alt</span>
|
<span class={styles.shortcutButton}>Alt</span>
|
||||||
|
@ -210,7 +208,7 @@ export const Panel = (props: Props) => {
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{t('header 3')}
|
{t('Header 3').toLocaleLowerCase()}
|
||||||
<span class={styles.shortcut}>
|
<span class={styles.shortcut}>
|
||||||
<span class={styles.shortcutButton}>Ctrl</span>
|
<span class={styles.shortcutButton}>Ctrl</span>
|
||||||
<span class={styles.shortcutButton}>Alt</span>
|
<span class={styles.shortcutButton}>Alt</span>
|
||||||
|
@ -245,14 +243,14 @@ export const Panel = (props: Props) => {
|
||||||
|
|
||||||
<section class={styles.shortcutList}>
|
<section class={styles.shortcutList}>
|
||||||
<p>
|
<p>
|
||||||
{t('cancel')}
|
{t('Cancel').toLocaleLowerCase()}
|
||||||
<span class={styles.shortcut}>
|
<span class={styles.shortcut}>
|
||||||
<span class={styles.shortcutButton}>Ctrl</span>
|
<span class={styles.shortcutButton}>Ctrl</span>
|
||||||
<span class={styles.shortcutButton}>Z</span>
|
<span class={styles.shortcutButton}>Z</span>
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{t('repeat')}
|
{t('Repeat').toLocaleLowerCase()}
|
||||||
<span class={styles.shortcut}>
|
<span class={styles.shortcut}>
|
||||||
<span class={styles.shortcutButton}>Ctrl</span>
|
<span class={styles.shortcutButton}>Ctrl</span>
|
||||||
<span class={styles.shortcutButton}>Shift</span>
|
<span class={styles.shortcutButton}>Shift</span>
|
||||||
|
|
|
@ -86,25 +86,25 @@ mark.highlight {
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-float='half-left'] {
|
[data-float='half-left'] {
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
max-width: 50%;
|
||||||
|
min-width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
float: left;
|
float: left;
|
||||||
margin: 1rem 1rem 0;
|
margin: 1rem 1rem 0;
|
||||||
clear: left;
|
clear: left;
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
|
||||||
max-width: 50%;
|
|
||||||
min-width: 30%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-float='half-right'] {
|
[data-float='half-right'] {
|
||||||
float: right;
|
|
||||||
margin: 1rem 0;
|
|
||||||
clear: right;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
max-width: 50%;
|
max-width: 50%;
|
||||||
min-width: 30%;
|
min-width: 30%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float: right;
|
||||||
|
margin: 1rem 0;
|
||||||
|
clear: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,23 +137,8 @@ mark.highlight {
|
||||||
}
|
}
|
||||||
|
|
||||||
&[data-type='punchline'] {
|
&[data-type='punchline'] {
|
||||||
border: solid #000;
|
|
||||||
border-width: 2px 0;
|
|
||||||
|
|
||||||
@include font-size(3.2rem);
|
@include font-size(3.2rem);
|
||||||
|
|
||||||
font-weight: 700;
|
|
||||||
line-height: 1.2;
|
|
||||||
margin: 1em 0;
|
|
||||||
padding: 2.4rem 0;
|
|
||||||
|
|
||||||
&[data-float='left'],
|
|
||||||
&[data-float='right'] {
|
|
||||||
@include font-size(2.2rem);
|
|
||||||
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
@include media-breakpoint-up(sm) {
|
||||||
&[data-float='left'] {
|
&[data-float='left'] {
|
||||||
margin-right: 1.5em;
|
margin-right: 1.5em;
|
||||||
|
@ -165,18 +150,26 @@ mark.highlight {
|
||||||
clear: right;
|
clear: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
border: solid #000;
|
||||||
|
border-width: 2px 0;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin: 1em 0;
|
||||||
|
padding: 2.4rem 0;
|
||||||
|
|
||||||
|
&[data-float='left'],
|
||||||
|
&[data-float='right'] {
|
||||||
|
@include font-size(2.2rem);
|
||||||
|
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ProseMirror article[data-type='incut'] {
|
.ProseMirror article[data-type='incut'] {
|
||||||
background: #f1f2f3;
|
|
||||||
|
|
||||||
@include font-size(1.4rem);
|
@include font-size(1.4rem);
|
||||||
|
|
||||||
margin: 1em -1rem;
|
|
||||||
padding: 2em 2rem;
|
|
||||||
transition: background 0.3s ease-in-out;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
@include media-breakpoint-up(sm) {
|
||||||
margin-left: -2rem;
|
margin-left: -2rem;
|
||||||
margin-right: -2rem;
|
margin-right: -2rem;
|
||||||
|
@ -193,6 +186,11 @@ mark.highlight {
|
||||||
margin-right: -3em;
|
margin-right: -3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
background: #f1f2f3;
|
||||||
|
margin: 1em -1rem;
|
||||||
|
padding: 2em 2rem;
|
||||||
|
transition: background 0.3s ease-in-out;
|
||||||
|
|
||||||
&[data-float] img {
|
&[data-float] img {
|
||||||
float: none;
|
float: none;
|
||||||
max-width: unset;
|
max-width: unset;
|
||||||
|
@ -202,9 +200,6 @@ mark.highlight {
|
||||||
|
|
||||||
&[data-float='left'],
|
&[data-float='left'],
|
||||||
&[data-float='half-left'] {
|
&[data-float='half-left'] {
|
||||||
margin-left: -1rem;
|
|
||||||
clear: left;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
@include media-breakpoint-up(sm) {
|
||||||
margin-left: -2rem;
|
margin-left: -2rem;
|
||||||
margin-right: 2rem;
|
margin-right: 2rem;
|
||||||
|
@ -217,13 +212,13 @@ mark.highlight {
|
||||||
@include media-breakpoint-up(xl) {
|
@include media-breakpoint-up(xl) {
|
||||||
margin-left: -12.5%;
|
margin-left: -12.5%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
margin-left: -1rem;
|
||||||
|
clear: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
&[data-float='right'],
|
&[data-float='right'],
|
||||||
&[data-float='half-right'] {
|
&[data-float='half-right'] {
|
||||||
margin-right: -1rem;
|
|
||||||
clear: right;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
@include media-breakpoint-up(sm) {
|
||||||
margin-left: 2rem;
|
margin-left: 2rem;
|
||||||
margin-right: -2rem;
|
margin-right: -2rem;
|
||||||
|
@ -236,6 +231,9 @@ mark.highlight {
|
||||||
@include media-breakpoint-up(xl) {
|
@include media-breakpoint-up(xl) {
|
||||||
margin-right: -12.5%;
|
margin-right: -12.5%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
margin-right: -1rem;
|
||||||
|
clear: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
*:last-child {
|
*:last-child {
|
||||||
|
|
|
@ -20,13 +20,13 @@ import {
|
||||||
useEditorIsFocused
|
useEditorIsFocused
|
||||||
} from 'solid-tiptap'
|
} from 'solid-tiptap'
|
||||||
|
|
||||||
|
import { useEditorContext } from '~/context/editor'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { UploadedFile } from '~/types/upload'
|
import { UploadedFile } from '~/types/upload'
|
||||||
import { useEditorContext } from '../../context/editor'
|
|
||||||
import { useLocalize } from '../../context/localize'
|
|
||||||
import { Modal } from '../Nav/Modal'
|
|
||||||
import { Button } from '../_shared/Button'
|
import { Button } from '../_shared/Button'
|
||||||
import { Icon } from '../_shared/Icon'
|
import { Icon } from '../_shared/Icon'
|
||||||
import { Loading } from '../_shared/Loading'
|
import { Loading } from '../_shared/Loading'
|
||||||
|
import { Modal } from '../_shared/Modal'
|
||||||
import { Popover } from '../_shared/Popover'
|
import { Popover } from '../_shared/Popover'
|
||||||
import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient'
|
import { ShowOnlyOnClient } from '../_shared/ShowOnlyOnClient'
|
||||||
import { LinkBubbleMenuModule } from './LinkBubbleMenu'
|
import { LinkBubbleMenuModule } from './LinkBubbleMenu'
|
||||||
|
|
|
@ -4,9 +4,9 @@ import { clsx } from 'clsx'
|
||||||
import { Match, Show, Switch, createEffect, createSignal, lazy, onCleanup, onMount } from 'solid-js'
|
import { Match, Show, Switch, createEffect, createSignal, lazy, onCleanup, onMount } from 'solid-js'
|
||||||
import { createEditorTransaction } from 'solid-tiptap'
|
import { createEditorTransaction } from 'solid-tiptap'
|
||||||
|
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
import { Icon } from '../../_shared/Icon'
|
import { Popover } from '~/components/_shared/Popover'
|
||||||
import { Popover } from '../../_shared/Popover'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { InsertLinkForm } from '../InsertLinkForm'
|
import { InsertLinkForm } from '../InsertLinkForm'
|
||||||
|
|
||||||
import styles from './TextBubbleMenu.module.scss'
|
import styles from './TextBubbleMenu.module.scss'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Show, createSignal } from 'solid-js'
|
import { For, Show, createSignal } from 'solid-js'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import type { Topic } from '~/graphql/schema/core.gen'
|
import type { Topic } from '~/graphql/schema/core.gen'
|
||||||
import { useLocalize } from '../../../context/localize'
|
|
||||||
import styles from './TopicSelect.module.scss'
|
import styles from './TopicSelect.module.scss'
|
||||||
|
|
||||||
type TopicSelectProps = {
|
type TopicSelectProps = {
|
||||||
|
|
|
@ -2,15 +2,14 @@ import { UploadFile, createDropzone, createFileUploader } from '@solid-primitive
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Show, createSignal } from 'solid-js'
|
import { Show, createSignal } from 'solid-js'
|
||||||
|
|
||||||
|
import { Button } from '~/components/_shared/Button'
|
||||||
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
|
import { Loading } from '~/components/_shared/Loading'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
|
import { useSession } from '~/context/session'
|
||||||
import { useUI } from '~/context/ui'
|
import { useUI } from '~/context/ui'
|
||||||
|
import { handleImageUpload } from '~/lib/handleImageUpload'
|
||||||
import { UploadedFile } from '~/types/upload'
|
import { UploadedFile } from '~/types/upload'
|
||||||
import { useLocalize } from '../../../context/localize'
|
|
||||||
import { useSession } from '../../../context/session'
|
|
||||||
import { handleImageUpload } from '../../../utils/handleImageUpload'
|
|
||||||
import { verifyImg } from '../../../utils/verifyImg'
|
|
||||||
import { Button } from '../../_shared/Button'
|
|
||||||
import { Icon } from '../../_shared/Icon'
|
|
||||||
import { Loading } from '../../_shared/Loading'
|
|
||||||
import { InlineForm } from '../InlineForm'
|
import { InlineForm } from '../InlineForm'
|
||||||
|
|
||||||
import styles from './UploadModalContent.module.scss'
|
import styles from './UploadModalContent.module.scss'
|
||||||
|
@ -19,6 +18,9 @@ type Props = {
|
||||||
onClose: (image?: UploadedFile) => void
|
onClose: (image?: UploadedFile) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const verify = (url: string) =>
|
||||||
|
fetch(url, { method: 'HEAD' }).then((res) => res.headers.get('Content-Type')?.startsWith('image'))
|
||||||
|
|
||||||
export const UploadModalContent = (props: Props) => {
|
export const UploadModalContent = (props: Props) => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
const { hideModal } = useUI()
|
const { hideModal } = useUI()
|
||||||
|
@ -87,7 +89,7 @@ export const UploadModalContent = (props: Props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleValidate = async (value: string) => {
|
const handleValidate = async (value: string) => {
|
||||||
const validationResult = await verifyImg(value)
|
const validationResult = await verify(value)
|
||||||
if (!validationResult) {
|
if (!validationResult) {
|
||||||
return t('Invalid image URL')
|
return t('Invalid image URL')
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,11 @@ import { createDropzone } from '@solid-primitives/upload'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Show, createSignal } from 'solid-js'
|
import { For, Show, createSignal } from 'solid-js'
|
||||||
|
|
||||||
|
import { VideoPlayer } from '~/components/_shared/VideoPlayer'
|
||||||
|
import { useLocalize } from '~/context/localize'
|
||||||
import { useSnackbar } from '~/context/ui'
|
import { useSnackbar } from '~/context/ui'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { composeMediaItems } from '~/lib/composeMediaItems'
|
||||||
import { composeMediaItems } from '../../../utils/composeMediaItems'
|
import { validateUrl } from '~/utils/validate'
|
||||||
import { validateUrl } from '../../../utils/validateUrl'
|
|
||||||
import { VideoPlayer } from '../../_shared/VideoPlayer'
|
|
||||||
|
|
||||||
import { MediaItem } from '~/types/mediaitem'
|
import { MediaItem } from '~/types/mediaitem'
|
||||||
import styles from './VideoUploader.module.scss'
|
import styles from './VideoUploader.module.scss'
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
.shoutCard {
|
.shoutCard {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
line-height: 1.2;
|
|
||||||
margin-bottom: 2.4rem;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-bottom: 2.4rem;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
.shoutCardCover {
|
.shoutCardCover {
|
||||||
img,
|
img,
|
||||||
|
@ -437,18 +437,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutCardWithCover {
|
.shoutCardWithCover {
|
||||||
aspect-ratio: 16/9;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(xl) {
|
@include media-breakpoint-down(xl) {
|
||||||
aspect-ratio: auto;
|
aspect-ratio: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
swiper-slide & {
|
aspect-ratio: 16/9;
|
||||||
aspect-ratio: 16/9;
|
width: 100%;
|
||||||
margin-bottom: 0;
|
|
||||||
|
|
||||||
|
swiper-slide & {
|
||||||
@include media-breakpoint-down(lg) {
|
@include media-breakpoint-down(lg) {
|
||||||
aspect-ratio: 1/1;
|
aspect-ratio: 1/1;
|
||||||
}
|
}
|
||||||
|
@ -464,6 +461,9 @@
|
||||||
padding-left: 10%;
|
padding-left: 10%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aspect-ratio: 16/9;
|
||||||
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.shoutCardNoImage {
|
&.shoutCardNoImage {
|
||||||
|
@ -501,15 +501,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutCardContent {
|
.shoutCardContent {
|
||||||
|
@include media-breakpoint-down(xl) {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: end;
|
justify-content: end;
|
||||||
padding: 30% 2.4rem 2.4rem;
|
padding: 30% 2.4rem 2.4rem;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
@include media-breakpoint-down(xl) {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutCardCover {
|
.shoutCardCover {
|
||||||
|
@ -656,12 +656,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutCardVertical {
|
.shoutCardVertical {
|
||||||
aspect-ratio: auto;
|
|
||||||
height: 100%;
|
|
||||||
min-height: 250px;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
@include media-breakpoint-up(sm) {
|
||||||
aspect-ratio: 2/1;
|
aspect-ratio: 2/1;
|
||||||
}
|
}
|
||||||
|
@ -674,13 +668,19 @@
|
||||||
aspect-ratio: 1/1.6;
|
aspect-ratio: 1/1.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aspect-ratio: auto;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 250px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
.shoutCardTitle,
|
.shoutCardTitle,
|
||||||
.shoutCardSubtitle {
|
.shoutCardSubtitle {
|
||||||
font-size: 2.2rem !important;
|
|
||||||
|
|
||||||
@include media-breakpoint-between(lg, xl) {
|
@include media-breakpoint-between(lg, xl) {
|
||||||
font-size: 1.8rem !important;
|
font-size: 1.8rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
font-size: 2.2rem !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shoutCardContent {
|
.shoutCardContent {
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
import { A, useNavigate, useSearchParams } from '@solidjs/router'
|
import { A, useNavigate, useSearchParams } from '@solidjs/router'
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Accessor, For, Show, createMemo, createSignal } from 'solid-js'
|
import { Accessor, For, Show, createMemo, createSignal } from 'solid-js'
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
import { useSession } from '../../../context/session'
|
import { Image } from '~/components/_shared/Image'
|
||||||
import type { Author, Maybe, Shout, Topic } from '../../../graphql/schema/core.gen'
|
import { Popover } from '~/components/_shared/Popover'
|
||||||
import { capitalize } from '../../../utils/capitalize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { getDescription } from '../../../utils/meta'
|
import { useSession } from '~/context/session'
|
||||||
|
import type { Author, Maybe, Shout, Topic } from '~/graphql/schema/core.gen'
|
||||||
|
import { capitalize } from '~/utils/capitalize'
|
||||||
|
import { descFromBody } from '~/utils/meta'
|
||||||
import { CoverImage } from '../../Article/CoverImage'
|
import { CoverImage } from '../../Article/CoverImage'
|
||||||
import { RatingControl as ShoutRatingControl } from '../../Article/RatingControl'
|
import { RatingControl as ShoutRatingControl } from '../../Article/RatingControl'
|
||||||
import { SharePopup, getShareUrl } from '../../Article/SharePopup'
|
import { SharePopup, getShareUrl } from '../../Article/SharePopup'
|
||||||
import { AuthorLink } from '../../Author/AuthorLink'
|
import { AuthorLink } from '../../Author/AuthorLink'
|
||||||
import stylesHeader from '../../Nav/Header/Header.module.scss'
|
import stylesHeader from '../../HeaderNav/Header.module.scss'
|
||||||
import { Icon } from '../../_shared/Icon'
|
|
||||||
import { Image } from '../../_shared/Image'
|
|
||||||
import { Popover } from '../../_shared/Popover'
|
|
||||||
import { CardTopic } from '../CardTopic'
|
import { CardTopic } from '../CardTopic'
|
||||||
import { FeedArticlePopup } from '../FeedArticlePopup'
|
import { FeedArticlePopup } from '../FeedArticlePopup'
|
||||||
import styles from './ArticleCard.module.scss'
|
import styles from './ArticleCard.module.scss'
|
||||||
|
@ -109,7 +109,7 @@ export const ArticleCard = (props: ArticleCardProps) => {
|
||||||
const [isActionPopupActive, setIsActionPopupActive] = createSignal(false)
|
const [isActionPopupActive, setIsActionPopupActive] = createSignal(false)
|
||||||
const [isCoverImageLoadError, setIsCoverImageLoadError] = createSignal(false)
|
const [isCoverImageLoadError, setIsCoverImageLoadError] = createSignal(false)
|
||||||
const [isCoverImageLoading, setIsCoverImageLoading] = createSignal(true)
|
const [isCoverImageLoading, setIsCoverImageLoading] = createSignal(true)
|
||||||
const description = getDescription(props.article?.body)
|
const description = descFromBody(props.article?.body)
|
||||||
const aspectRatio: Accessor<string> = () => LAYOUT_ASPECT[props.article?.layout as string]
|
const aspectRatio: Accessor<string> = () => LAYOUT_ASPECT[props.article?.layout as string]
|
||||||
const [mainTopicTitle, mainTopicSlug] = getMainTopicTitle(props.article, lang())
|
const [mainTopicTitle, mainTopicSlug] = getMainTopicTitle(props.article, lang())
|
||||||
const { title, subtitle } = getTitleAndSubtitle(props.article)
|
const { title, subtitle } = getTitleAndSubtitle(props.article)
|
||||||
|
@ -128,7 +128,7 @@ export const ArticleCard = (props: ArticleCardProps) => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const scrollToComments = (event: MouseEvent & { currentTarget: HTMLAnchorElement; target: Element }) => {
|
const scrollToComments = (event: MouseEvent & { currentTarget: HTMLAnchorElement; target: Element }) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
navigate(`/article/${props.article.slug}`)
|
navigate(`/${props.article.slug}`)
|
||||||
changeSearchParams({
|
changeSearchParams({
|
||||||
scrollTo: 'comments'
|
scrollTo: 'comments'
|
||||||
})
|
})
|
||||||
|
@ -220,7 +220,7 @@ export const ArticleCard = (props: ArticleCardProps) => {
|
||||||
[styles.shoutCardTitlesContainerFeedMode]: props.settings?.isFeedMode
|
[styles.shoutCardTitlesContainerFeedMode]: props.settings?.isFeedMode
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<A href={`/article${props.article?.slug || ''}`}>
|
<A href={`/${props.article?.slug || ''}`}>
|
||||||
<div class={styles.shoutCardTitle}>
|
<div class={styles.shoutCardTitle}>
|
||||||
<span class={styles.shoutCardLinkWrapper}>
|
<span class={styles.shoutCardLinkWrapper}>
|
||||||
<span class={styles.shoutCardLinkContainer} innerHTML={title} />
|
<span class={styles.shoutCardLinkContainer} innerHTML={title} />
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
.besideColumn {
|
.besideColumn {
|
||||||
counter-reset: item;
|
|
||||||
list-style-type: none;
|
|
||||||
padding-left: 0;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
counter-reset: item;
|
||||||
|
list-style-type: none;
|
||||||
|
padding-left: 0;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// TODO: additional entities list column + article
|
// TODO: additional entities list column + article
|
||||||
|
|
||||||
import type { Author, Shout, Topic } from '../../graphql/schema/core.gen'
|
import type { Author, Shout, Topic } from '~/graphql/schema/core.gen'
|
||||||
|
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Show } from 'solid-js'
|
import { For, Show } from 'solid-js'
|
||||||
import { useLocalize } from '../../context/localize'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { AuthorBadge } from '../Author/AuthorBadge'
|
import { AuthorBadge } from '../Author/AuthorBadge'
|
||||||
import { TopicCard } from '../Topic/Card'
|
import { TopicCard } from '../Topic/Card'
|
||||||
import { Icon } from '../_shared/Icon'
|
import { Icon } from '../_shared/Icon'
|
||||||
|
@ -48,14 +48,14 @@ export const Beside = (props: Props) => {
|
||||||
<h4>{props.title}</h4>
|
<h4>{props.title}</h4>
|
||||||
|
|
||||||
<Show when={props.wrapper === 'author'}>
|
<Show when={props.wrapper === 'author'}>
|
||||||
<a href="/authors">
|
<a href="/author">
|
||||||
{t('All authors')}
|
{t('All authors')}
|
||||||
<Icon name="arrow-right" class={styles.icon} />
|
<Icon name="arrow-right" class={styles.icon} />
|
||||||
</a>
|
</a>
|
||||||
</Show>
|
</Show>
|
||||||
|
|
||||||
<Show when={props.wrapper === 'topic'}>
|
<Show when={props.wrapper === 'topic'}>
|
||||||
<a href="/topics">
|
<a href="/topic">
|
||||||
{t('All topics')}
|
{t('All topics')}
|
||||||
<Icon name="arrow-right" class={styles.icon} />
|
<Icon name="arrow-right" class={styles.icon} />
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
.feedArticlePopup {
|
.feedArticlePopup {
|
||||||
padding: 0 !important;
|
|
||||||
text-align: left;
|
|
||||||
overflow: hidden;
|
|
||||||
margin-top: -14px;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(md) {
|
@include media-breakpoint-down(md) {
|
||||||
left: auto !important;
|
left: auto !important;
|
||||||
right: 0;
|
right: 0;
|
||||||
transform: none !important;
|
transform: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
padding: 0 !important;
|
||||||
|
text-align: left;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: -14px;
|
||||||
|
|
||||||
.actionList {
|
.actionList {
|
||||||
& > li {
|
& > li {
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import type { PopupProps } from '../../_shared/Popup'
|
import type { PopupProps } from '~/components/_shared/Popup'
|
||||||
|
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { Show, createSignal } from 'solid-js'
|
import { Show, createSignal } from 'solid-js'
|
||||||
|
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
import { Icon } from '../../_shared/Icon'
|
import { Popup } from '~/components/_shared/Popup'
|
||||||
import { Popup } from '../../_shared/Popup'
|
import { SoonChip } from '~/components/_shared/SoonChip'
|
||||||
import { SoonChip } from '../../_shared/SoonChip'
|
import { useLocalize } from '~/context/localize'
|
||||||
|
|
||||||
import styles from './FeedArticlePopup.module.scss'
|
import styles from './FeedArticlePopup.module.scss'
|
||||||
|
|
||||||
|
@ -93,10 +93,10 @@ export const FeedArticlePopup = (props: Props) => {
|
||||||
{/* class={styles.action}*/}
|
{/* class={styles.action}*/}
|
||||||
{/* role="button"*/}
|
{/* role="button"*/}
|
||||||
{/* onClick={() => {*/}
|
{/* onClick={() => {*/}
|
||||||
{/* alert('Report')*/}
|
{/* alert('Complain')*/}
|
||||||
{/* }}*/}
|
{/* }}*/}
|
||||||
{/* >*/}
|
{/* >*/}
|
||||||
{/* {t('Report')}*/}
|
{/* {t('Complain')}*/}
|
||||||
{/* </button>*/}
|
{/* </button>*/}
|
||||||
{/* </li>*/}
|
{/* </li>*/}
|
||||||
{/*</Show>*/}
|
{/*</Show>*/}
|
||||||
|
|
|
@ -35,9 +35,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.floor--group {
|
.floor--group {
|
||||||
background: #e8e5f0;
|
|
||||||
padding: 4rem 0 0;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
padding-bottom: 3rem;
|
padding-bottom: 3rem;
|
||||||
}
|
}
|
||||||
|
@ -49,4 +46,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
background: #e8e5f0;
|
||||||
|
padding: 4rem 0 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { JSX } from 'solid-js/jsx-runtime'
|
import type { JSX } from 'solid-js/jsx-runtime'
|
||||||
import type { Shout } from '../../graphql/schema/core.gen'
|
import type { Shout } from '~/graphql/schema/core.gen'
|
||||||
|
|
||||||
import { For, Show } from 'solid-js'
|
import { For, Show } from 'solid-js'
|
||||||
|
|
||||||
|
|
|
@ -12,12 +12,11 @@
|
||||||
|
|
||||||
button,
|
button,
|
||||||
.button {
|
.button {
|
||||||
|
@include font-size(1.5rem);
|
||||||
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 1.2rem;
|
border-radius: 1.2rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
@include font-size(1.5rem);
|
|
||||||
|
|
||||||
gap: 0.6rem;
|
gap: 0.6rem;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-top: 3rem;
|
margin-top: 3rem;
|
||||||
|
@ -32,14 +31,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.placeholder--feed-mode {
|
.placeholder--feed-mode {
|
||||||
flex-direction: column;
|
|
||||||
min-height: 40rem;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(lg) {
|
@include media-breakpoint-up(lg) {
|
||||||
aspect-ratio: 1 / 0.8;
|
aspect-ratio: 1 / 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 40rem;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
.placeholderCover {
|
.placeholderCover {
|
||||||
flex: 1 100%;
|
flex: 1 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -68,8 +67,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.placeholder--profile-mode {
|
.placeholder--profile-mode {
|
||||||
min-height: 40rem;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(lg) {
|
@include media-breakpoint-down(lg) {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
@ -79,36 +76,30 @@
|
||||||
min-height: auto;
|
min-height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.placeholderCover {
|
min-height: 40rem;
|
||||||
flex: 1;
|
|
||||||
padding: 1.6rem;
|
|
||||||
|
|
||||||
|
.placeholderCover {
|
||||||
@include media-breakpoint-up(lg) {
|
@include media-breakpoint-up(lg) {
|
||||||
order: 2;
|
order: 2;
|
||||||
position: static;
|
position: static;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flex: 1;
|
||||||
|
padding: 1.6rem;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
@include media-breakpoint-up(lg) {
|
||||||
|
object-position: right;
|
||||||
|
}
|
||||||
|
|
||||||
aspect-ratio: 16/10;
|
aspect-ratio: 16/10;
|
||||||
min-width: 40rem;
|
min-width: 40rem;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@include media-breakpoint-up(lg) {
|
|
||||||
object-position: right;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.placeholderContent {
|
.placeholderContent {
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
font-size: 1.4rem;
|
|
||||||
line-height: 1.2;
|
|
||||||
min-width: 60%;
|
|
||||||
padding: 0 2rem 2rem;
|
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
padding: 3rem;
|
padding: 3rem;
|
||||||
|
@ -117,6 +108,14 @@
|
||||||
@include media-breakpoint-up(lg) {
|
@include media-breakpoint-up(lg) {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
min-width: 60%;
|
||||||
|
padding: 0 2rem 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
|
@ -124,6 +123,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
|
@include media-breakpoint-up(lg) {
|
||||||
|
left: auto;
|
||||||
|
position: absolute;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
background: var(--background-color-invert);
|
background: var(--background-color-invert);
|
||||||
bottom: 2rem;
|
bottom: 2rem;
|
||||||
color: var(--default-color-invert);
|
color: var(--default-color-invert);
|
||||||
|
@ -132,12 +137,6 @@
|
||||||
right: 2rem;
|
right: 2rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@include media-breakpoint-up(lg) {
|
|
||||||
left: auto;
|
|
||||||
position: absolute;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
filter: invert(1);
|
filter: invert(1);
|
||||||
}
|
}
|
||||||
|
@ -156,13 +155,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.placeholderContent {
|
.placeholderContent {
|
||||||
padding: 1.6rem;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(lg) {
|
@include media-breakpoint-down(lg) {
|
||||||
br {
|
br {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
padding: 1.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.placeholder--feedMy,
|
.placeholder--feedMy,
|
||||||
|
@ -234,17 +233,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottomLinks {
|
.bottomLinks {
|
||||||
display: flex;
|
|
||||||
|
|
||||||
@include font-size(1.6rem);
|
@include font-size(1.6rem);
|
||||||
|
|
||||||
gap: 4rem;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(sm) {
|
@include media-breakpoint-down(sm) {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1.4rem;
|
gap: 1.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
gap: 4rem;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
border: none !important;
|
border: none !important;
|
||||||
padding-left: 2.6rem;
|
padding-left: 2.6rem;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { clsx } from 'clsx'
|
import { clsx } from 'clsx'
|
||||||
import { For, Show, createMemo } from 'solid-js'
|
import { For, Show, createMemo } from 'solid-js'
|
||||||
|
|
||||||
import { useLocalize } from '../../../context/localize'
|
import { Icon } from '~/components/_shared/Icon'
|
||||||
import { useSession } from '../../../context/session'
|
import { useLocalize } from '~/context/localize'
|
||||||
import { Icon } from '../../_shared/Icon'
|
import { useSession } from '~/context/session'
|
||||||
import styles from './Placeholder.module.scss'
|
import styles from './Placeholder.module.scss'
|
||||||
|
|
||||||
type ProfileLink = {
|
type ProfileLink = {
|
||||||
|
@ -36,14 +36,14 @@ const data: PlaceholderData = {
|
||||||
text: 'Placeholder feed',
|
text: 'Placeholder feed',
|
||||||
buttonLabelAuthor: 'Popular authors',
|
buttonLabelAuthor: 'Popular authors',
|
||||||
buttonLabelFeed: 'Create own feed',
|
buttonLabelFeed: 'Create own feed',
|
||||||
href: '/authors?by=followers'
|
href: '/author?by=followers'
|
||||||
},
|
},
|
||||||
feedCollaborations: {
|
feedCollaborations: {
|
||||||
image: 'placeholder-experts.webp',
|
image: 'placeholder-experts.webp',
|
||||||
header: 'Find collaborators',
|
header: 'Find collaborators',
|
||||||
text: 'Placeholder feedCollaborations',
|
text: 'Placeholder feedCollaborations',
|
||||||
buttonLabel: 'Find co-authors',
|
buttonLabel: 'Find co-authors',
|
||||||
href: '/authors?by=name'
|
href: '/author?by=name'
|
||||||
},
|
},
|
||||||
feedDiscussions: {
|
feedDiscussions: {
|
||||||
image: 'placeholder-discussions.webp',
|
image: 'placeholder-discussions.webp',
|
||||||
|
@ -51,14 +51,14 @@ const data: PlaceholderData = {
|
||||||
text: 'Placeholder feedDiscussions',
|
text: 'Placeholder feedDiscussions',
|
||||||
buttonLabelAuthor: 'Current discussions',
|
buttonLabelAuthor: 'Current discussions',
|
||||||
buttonLabelFeed: 'Enter',
|
buttonLabelFeed: 'Enter',
|
||||||
href: '/feed?by=last_comment'
|
href: '/feed/hot'
|
||||||
},
|
},
|
||||||
author: {
|
author: {
|
||||||
image: 'placeholder-join.webp',
|
image: 'placeholder-join.webp',
|
||||||
header: 'Join our team of authors',
|
header: 'Join our team of authors',
|
||||||
text: 'Join our team of authors text',
|
text: 'Join our team of authors text',
|
||||||
buttonLabel: 'Create post',
|
buttonLabel: 'Create post',
|
||||||
href: '/create',
|
href: '/edit/new',
|
||||||
profileLinks: [
|
profileLinks: [
|
||||||
{
|
{
|
||||||
href: '/how-to-write-a-good-article',
|
href: '/how-to-write-a-good-article',
|
||||||
|
@ -71,14 +71,14 @@ const data: PlaceholderData = {
|
||||||
header: 'Join discussions',
|
header: 'Join discussions',
|
||||||
text: 'Placeholder feedDiscussions',
|
text: 'Placeholder feedDiscussions',
|
||||||
buttonLabel: 'Go to discussions',
|
buttonLabel: 'Go to discussions',
|
||||||
href: '/feed?by=last_comment',
|
href: '/feed/hot',
|
||||||
profileLinks: [
|
profileLinks: [
|
||||||
{
|
{
|
||||||
href: '/about/discussion-rules',
|
href: '/debate',
|
||||||
label: 'Discussion rules'
|
label: 'Discussion rules'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: '/about/discussion-rules#ban',
|
href: '/debate#ban',
|
||||||
label: 'Block rules'
|
label: 'Block rules'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user