diff --git a/.dockerignore b/.dockerignore index 0ec9738d..1168d108 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,8 +2,6 @@ node_modules out dist -.husky -.next .idea .history .vscode diff --git a/.drone.yml b/.drone.yml index 695a9504..0d9eefa7 100644 --- a/.drone.yml +++ b/.drone.yml @@ -11,10 +11,10 @@ steps: image: plugins/docker when: branch: - - never + - master environment: - NEXT_PUBLIC_API_HOST: https://vault48.org/api/ - NEXT_PUBLIC_REMOTE_CURRENT: https://vault48.org/static/ + NEXT_PUBLIC_API_HOST: https://pig.vault48.org/ + NEXT_PUBLIC_REMOTE_CURRENT: https://pig.vault48.org/static/ NEXT_PUBLIC_PUBLIC_HOST: https://vault48.org/ NEXT_PUBLIC_BOT_USERNAME: vault48bot settings: diff --git a/.env.local b/.env.local index cf359933..7ce09d99 100644 --- a/.env.local +++ b/.env.local @@ -2,6 +2,6 @@ # NEXT_PUBLIC_REMOTE_CURRENT=https://pig.staging.vault48.org/static/ # NEXT_PUBLIC_API_HOST=http://localhost:7777/ # NEXT_PUBLIC_REMOTE_CURRENT=http://localhost:7777/static/ -NEXT_PUBLIC_API_HOST=https://vault48.org/api/ -NEXT_PUBLIC_REMOTE_CURRENT=https://vault48.org/static/ +NEXT_PUBLIC_API_HOST=https://pig.vault48.org/ +NEXT_PUBLIC_REMOTE_CURRENT=https://pig.vault48.org/static/ NEXT_PUBLIC_BOT_USERNAME=vault48testbot \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index e822b399..46b6af84 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,6 @@ module.exports = { extends: ['plugin:react/recommended', 'plugin:@next/next/recommended'], rules: { - 'prettier/prettier': 'error', 'react-hooks/rules-of-hooks': 'error', // Checks rules of Hooks 'react-hooks/exhaustive-deps': 'warn', // Checks effect dependencies 'react/prop-types': 0, @@ -10,21 +9,13 @@ module.exports = { '@next/next/no-img-element': 0, 'unused-imports/no-unused-imports': 'warn', // 'no-unused-vars': 'warn', - quotes: [2, 'single', { avoidEscape: true }], + 'quotes': [2, 'single', { 'avoidEscape': true }], 'import/order': [ 'error', { alphabetize: { order: 'asc' }, 'newlines-between': 'always', - groups: [ - 'builtin', - 'external', - 'internal', - 'parent', - 'sibling', - 'index', - 'unknown', - ], + groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'unknown'], pathGroups: [ { pattern: 'react', @@ -43,17 +34,18 @@ module.exports = { paths: [ { name: 'ramda', - message: "import from '~/utils/ramda' instead", + message: + 'import from \'~/utils/ramda\' instead', }, ], }, - ], + ] }, parserOptions: { ecmaVersion: 7, sourceType: 'module', }, - plugins: ['import', 'react-hooks', 'unused-imports', 'prettier'], + plugins: ['import', 'react-hooks', 'unused-imports'], parser: '@typescript-eslint/parser', settings: { react: { diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml deleted file mode 100644 index 1167a419..00000000 --- a/.forgejo/workflows/build.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: Build & Publish - -on: - push: - branches: [master] - -jobs: - push_to_registry: - name: Build & Publish - runs-on: ubuntu-22.04 - permissions: - packages: write - contents: read - attestations: write - id-token: write - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Registry Login - uses: docker/login-action@v3 - with: - registry: git.vault48.org - username: ${{ secrets.username }} - password: ${{ secrets.password }} - - - name: Extract docker metadata - id: meta - uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 - with: - images: git.vault48.org/${{ env.GITHUB_REPOSITORY }} - - - name: Build and push Docker image - id: push - uses: docker/build-push-action@v6 - with: - context: . - file: ./docker/nextjs-standalone/Dockerfile - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - build-args: | - NEXT_PUBLIC_API_HOST=https://vault48.org/api/ - NEXT_PUBLIC_REMOTE_CURRENT=https://vault48.org/static/ - NEXT_PUBLIC_PUBLIC_HOST=https://vault48.org/ - NEXT_PUBLIC_BOT_USERNAME=vault48bot \ No newline at end of file diff --git a/docker/nextjs-standalone/Dockerfile b/docker/nextjs-standalone/Dockerfile deleted file mode 100644 index c6f52021..00000000 --- a/docker/nextjs-standalone/Dockerfile +++ /dev/null @@ -1,51 +0,0 @@ -# As written here: -# https://dev.to/leduc1901/reduce-docker-image-size-for-your-nextjs-app-5911 - -# Base ─────────────────────────────────────────────────────────────────────── -FROM node:14-alpine as base - -WORKDIR /opt/app - -ENV PATH /opt/app/node_modules/.bin:$PATH - -# Build ────────────────────────────────────────────────────────────────────── -FROM base as builder - -ARG NEXT_PUBLIC_API_HOST -ARG NEXT_PUBLIC_REMOTE_CURRENT -ARG NEXT_PUBLIC_PUBLIC_HOST -ARG NEXT_PUBLIC_BOT_USERNAME - -ENV NEXT_PUBLIC_API_HOST $NEXT_PUBLIC_API_HOST -ENV NEXT_PUBLIC_REMOTE_CURRENT $NEXT_PUBLIC_REMOTE_CURRENT -ENV NEXT_PUBLIC_PUBLIC_HOST $NEXT_PUBLIC_PUBLIC_HOST -ENV NEXT_PUBLIC_BOT_USERNAME $NEXT_PUBLIC_BOT_USERNAME - -# ENV NEXT_PUBLIC_API_HOST https://vault48.org/api/ -# ENV NEXT_PUBLIC_REMOTE_CURRENT https://vault48.org/static/ -# ENV NEXT_PUBLIC_PUBLIC_HOST https://vault48.org/ -# ENV NEXT_PUBLIC_BOT_USERNAME vault48bot - -COPY package.json . -COPY yarn.lock . - -RUN true \ - && yarn install --frozen-lockfile\ - && true - -COPY . /opt/app - -# pkg packs nodejs with given script, so we don't need it in next section -RUN yarn next build - -FROM node:14-alpine as runner - -WORKDIR /opt/app - -COPY --from=builder /opt/app/public ./public -COPY --from=builder /opt/app/.next/standalone . -COPY --from=builder /opt/app/.next/static ./.next/static - -EXPOSE 3000 - -ENTRYPOINT ["node", "server.js"] \ No newline at end of file diff --git a/next.config.js b/next.config.js index c95c6aa1..8fb923d7 100644 --- a/next.config.js +++ b/next.config.js @@ -2,49 +2,44 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', }); -const withTM = require('next-transpile-modules')([ - 'ramda', - '@v9v/ts-react-telegram-login', -]); +const withTM = require('next-transpile-modules')(['ramda', '@v9v/ts-react-telegram-login']); module.exports = withBundleAnalyzer( withTM({ - output: 'standalone', /** rewrite old-style node paths */ async rewrites() { return [ { - // everything except 'post' is for backwards compatibility here - source: '/(post|photo|blog|song|video|cell):id', + source: '/post:id', destination: '/node/:id', }, { source: '/~:username', destination: '/profile/:username', - }, + } ]; }, /** don't try to optimize fonts */ optimizeFonts: false, images: { - remotePatterns: [ - { - protocol: 'https', - hostname: 'vault48.org', - pathname: '/static/**', - }, - { - protocol: 'https', - hostname: '*.ytimg.com', - pathname: '/**', - }, - { - protocol: 'http', - hostname: 'localhost', - pathname: '/**', - }, - ], - }, - }), + remotePatterns: [ + { + protocol: 'https', + hostname: '*.vault48.org', + pathname: '/**', + }, + { + protocol: 'https', + hostname: '*.ytimg.com', + pathname: '/**', + }, + { + protocol: 'http', + hostname: 'localhost', + pathname: '/**', + }, + ], + }, + }) ); diff --git a/package.json b/package.json index 43e726e8..10e5589c 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "mobx-persist-store": "^1.0.4", "mobx-react-lite": "^3.2.3", "next": "^12.3.0", - "photoswipe": "^5.4.4", + "photoswipe": "^4.1.3", "raleway-cyrillic": "^4.0.2", "ramda": "^0.26.1", "react": "^17.0.2", @@ -36,13 +36,12 @@ "react-lazyload": "^3.2.0", "react-masonry-css": "^1.0.16", "react-popper": "^2.2.3", - "react-resize-detector": "^12.0.2", "react-router": "^5.1.2", "react-router-dom": "^5.1.2", "react-sticky-box": "^1.0.2", "sass": "^1.49.0", "sharp": "^0.32.6", - "swiper": "^11.2.2", + "swiper": "^11.0.3", "swr": "^1.0.1", "throttle-debounce": "^2.1.0", "typescript": "^4.0.5", @@ -93,14 +92,13 @@ "@typescript-eslint/parser": "^5.10.1", "eslint": "^7.32.0", "eslint-plugin-import": "^2.25.4", - "eslint-plugin-prettier": "^5.2.3", "eslint-plugin-react": "^7.28.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-unused-imports": "^3.0.0", "husky": "^7.0.4", "lint-staged": "^12.1.6", "next-transpile-modules": "^9.0.0", - "prettier": "^3.0.0" + "prettier": "^2.7.1" }, "lint-staged": { "./**/*.{js,jsx,ts,tsx}": [ diff --git a/public/images/sansivieria.svg b/public/images/sansivieria.svg deleted file mode 100644 index ff60a0da..00000000 --- a/public/images/sansivieria.svg +++ /dev/null @@ -1,752 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/components/common/Avatar/index.tsx b/src/components/common/Avatar/index.tsx index 946c63f9..dc35d469 100644 --- a/src/components/common/Avatar/index.tsx +++ b/src/components/common/Avatar/index.tsx @@ -14,7 +14,7 @@ interface Props extends DivProps { username?: string; size?: number; hasUpdates?: boolean; - preset?: (typeof imagePresets)[keyof typeof imagePresets]; + preset?: typeof imagePresets[keyof typeof imagePresets]; } const Avatar = forwardRef( diff --git a/src/components/common/Columns/index.tsx b/src/components/common/Columns/index.tsx index e491e77c..6901c609 100644 --- a/src/components/common/Columns/index.tsx +++ b/src/components/common/Columns/index.tsx @@ -31,7 +31,7 @@ const Columns: FC = ({ if (!childs) return; - const timeout = setTimeout(() => setColumns([...childs.values()]), 150); + const timeout = setTimeout(() => setColumns([...childs]), 150); return () => clearTimeout(timeout); // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/src/components/common/NodeHorizontalCard/index.tsx b/src/components/common/NodeHorizontalCard/index.tsx index 309110ea..3c0847be 100644 --- a/src/components/common/NodeHorizontalCard/index.tsx +++ b/src/components/common/NodeHorizontalCard/index.tsx @@ -8,8 +8,6 @@ import { URLS } from '~/constants/urls'; import { INode } from '~/types'; import { getPrettyDate } from '~/utils/dom'; -import { getNewCommentAnchor } from '../../../constants/dom/links'; - import styles from './styles.module.scss'; interface Props { @@ -18,34 +16,32 @@ interface Props { onClick?: MouseEventHandler; } -const NodeHorizontalCard: FC = ({ node, hasNew, onClick }) => ( - -
= ({ node, hasNew, onClick }) => { + return ( + - -
- -
-
{node.title || '...'}
- -
- {getPrettyDate(node.created_at)} +
+
-
- -); + +
+
{node.title || '...'}
+ +
+ {getPrettyDate(node.created_at)} +
+
+ + ); +}; export { NodeHorizontalCard }; diff --git a/src/components/common/NodeHorizontalCard/styles.module.scss b/src/components/common/NodeHorizontalCard/styles.module.scss index 6eb626c4..32007320 100644 --- a/src/components/common/NodeHorizontalCard/styles.module.scss +++ b/src/components/common/NodeHorizontalCard/styles.module.scss @@ -27,8 +27,8 @@ &.new { &::after { content: ' '; - width: 8px; - height: 8px; + width: 12px; + height: 12px; border-radius: 100%; background: $color_danger; box-shadow: $content_bg 0 0 0 5px; diff --git a/src/components/common/SubTitle/index.tsx b/src/components/common/SubTitle/index.tsx index e24510ea..ebfd8961 100644 --- a/src/components/common/SubTitle/index.tsx +++ b/src/components/common/SubTitle/index.tsx @@ -13,11 +13,9 @@ interface Props extends DivProps { const SubTitle: FC = ({ isLoading, children, ...rest }) => (
- - - {children} - - + + {children} +
); diff --git a/src/components/common/SubTitle/styles.module.scss b/src/components/common/SubTitle/styles.module.scss index c3a36b26..98651785 100644 --- a/src/components/common/SubTitle/styles.module.scss +++ b/src/components/common/SubTitle/styles.module.scss @@ -1,25 +1,7 @@ -@import 'src/styles/variables.scss'; +@import "src/styles/variables.scss"; .title { font: $font_12_semibold; text-transform: uppercase; - display: flex; - flex-direction: row; - align-items: center; - gap: $gap / 2; - color: var(--gray_75); - - a { - text-decoration: none; - color: inherit; - } - - &::after { - content: ' '; - display: flex; - height: 2px; - background-color: var(--gray_90); - flex: 1; - border-radius: 2px; - } + opacity: 0.3; } diff --git a/src/components/input/InputText/styles.module.scss b/src/components/input/InputText/styles.module.scss index 740fca00..1422f8fc 100644 --- a/src/components/input/InputText/styles.module.scss +++ b/src/components/input/InputText/styles.module.scss @@ -25,7 +25,7 @@ background: none; padding: 0 $gap 0 $gap; font: $font_14_semibold; - border-radius: $input_radius; + border-radius: $radius; } } diff --git a/src/components/input/InputWrapper/styles.module.scss b/src/components/input/InputWrapper/styles.module.scss index 5c588408..b200c3a2 100644 --- a/src/components/input/InputWrapper/styles.module.scss +++ b/src/components/input/InputWrapper/styles.module.scss @@ -5,7 +5,7 @@ background: $input_bg_color; min-height: $input_height; - border-radius: $input_radius; + border-radius: $radius; position: relative; color: $input_text_color; font: $input_font; diff --git a/src/components/node/NodeImageSwiperBlock/index.tsx b/src/components/node/NodeImageSwiperBlock/index.tsx index c3c778d3..9e5d8082 100644 --- a/src/components/node/NodeImageSwiperBlock/index.tsx +++ b/src/components/node/NodeImageSwiperBlock/index.tsx @@ -57,9 +57,7 @@ const NodeImageSwiperBlock: FC = observer(({ node }) => { useEffect(() => { controlledSwiper?.slideTo(0, 0); - return () => { - controlledSwiper?.slideTo(0, 0); - }; + return () => controlledSwiper?.slideTo(0, 0); }, [controlledSwiper, images, node.id]); useEffect(() => { diff --git a/src/components/node/NodeRelated/styles.module.scss b/src/components/node/NodeRelated/styles.module.scss index 7a26a31a..1d4de34d 100644 --- a/src/components/node/NodeRelated/styles.module.scss +++ b/src/components/node/NodeRelated/styles.module.scss @@ -29,6 +29,11 @@ .title { padding-left: 5px; + + a { + text-decoration: none; + color: inherit; + } } .text { diff --git a/src/components/notifications/NotificationComment/index.tsx b/src/components/notifications/NotificationComment/index.tsx index e707a27f..194a60bb 100644 --- a/src/components/notifications/NotificationComment/index.tsx +++ b/src/components/notifications/NotificationComment/index.tsx @@ -9,8 +9,6 @@ import { Square } from '~/components/common/Square'; import { NotificationItem } from '~/types/notifications'; import { formatText, getURLFromString } from '~/utils/dom'; -import { getCommentAnchor } from '../../../constants/dom/links'; - import styles from './styles.module.scss'; interface NotificationCommentProps { @@ -19,10 +17,7 @@ interface NotificationCommentProps { } const NotificationComment: FC = ({ item, isNew }) => ( - +
- `${CONFIG.apiHost}oauth/${provider}/redirect/`, + `${CONFIG.apiHost}oauth/${provider}/redirect`, ME: '/auth', UPDATE_PHOTO: '/auth/photo', UPDATE_COVER: '/auth/photo', - PROFILE: (username: string) => `/users/${username}`, + PROFILE: (username: string) => `/users/${username}/profile`, MESSAGES: (username: string) => `/users/${username}/messages`, MESSAGE_SEND: (username: string) => `/users/${username}/messages`, MESSAGE_DELETE: (username: string, id: number) => diff --git a/src/constants/comment.ts b/src/constants/comment.ts index a61d0339..cd3e5f2f 100644 --- a/src/constants/comment.ts +++ b/src/constants/comment.ts @@ -20,7 +20,7 @@ export const COMMENT_BLOCK_DETECTORS = [ ]; export type ICommentBlock = { - type: (typeof COMMENT_BLOCK_TYPES)[keyof typeof COMMENT_BLOCK_TYPES]; + type: typeof COMMENT_BLOCK_TYPES[keyof typeof COMMENT_BLOCK_TYPES]; content: string; }; diff --git a/src/constants/dom/index.ts b/src/constants/dom/index.ts index 3d9462a8..be18c3a4 100644 --- a/src/constants/dom/index.ts +++ b/src/constants/dom/index.ts @@ -5,5 +5,3 @@ export const isTablet = () => { return window.innerWidth < 599; }; - -export const headerHeight = 64; // px diff --git a/src/constants/dom/links.ts b/src/constants/dom/links.ts deleted file mode 100644 index 52933eae..00000000 --- a/src/constants/dom/links.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const NEW_COMMENT_ANCHOR_NAME = 'new-comment'; -export const COMMENT_ANCHOR_PREFIX = 'comment'; - -export const getCommentId = (id: number) => - [COMMENT_ANCHOR_PREFIX, id].join('-'); - -export const getNewCommentAnchor = (url: string) => - [url, NEW_COMMENT_ANCHOR_NAME].join('#'); - -export const getCommentAnchor = (url: string, commentId: number) => - [url, getCommentId(commentId)].join('#'); - -export const isCommentAnchor = (hash: string | undefined) => - hash?.startsWith(COMMENT_ANCHOR_PREFIX) || - hash?.startsWith(NEW_COMMENT_ANCHOR_NAME); diff --git a/src/constants/modal/index.ts b/src/constants/modal/index.ts index f72114fd..820f9962 100644 --- a/src/constants/modal/index.ts +++ b/src/constants/modal/index.ts @@ -1,5 +1,3 @@ -import { lazy } from 'react'; - import { LoginDialog } from '~/containers/auth/LoginDialog'; import { LoginSocialRegisterDialog } from '~/containers/auth/LoginSocialRegisterDialog'; import { RestorePasswordDialog } from '~/containers/auth/RestorePasswordDialog'; @@ -8,14 +6,9 @@ import { TelegramAttachDialog } from '~/containers/auth/TelegramAttachDialog'; import { EditorCreateDialog } from '~/containers/dialogs/EditorCreateDialog'; import { EditorEditDialog } from '~/containers/dialogs/EditorEditDialog'; import { LoadingDialog } from '~/containers/dialogs/LoadingDialog'; +import { PhotoSwipe } from '~/containers/dialogs/PhotoSwipe'; import { TestDialog } from '~/containers/dialogs/TestDialog'; -const PhotoSwipe = lazy(() => - import('~/containers/dialogs/PhotoSwipe').then((it) => ({ - default: it.PhotoSwipe, - })), -); - export enum Dialog { Login = 'Login', Register = 'Register', diff --git a/src/constants/sidebar/index.ts b/src/constants/sidebar/index.ts index abd3390a..587b493e 100644 --- a/src/constants/sidebar/index.ts +++ b/src/constants/sidebar/index.ts @@ -1,3 +1,4 @@ + export enum SidebarName { Settings = 'settings', Tag = 'tag', diff --git a/src/constants/themes/index.ts b/src/constants/themes/index.ts index b32d2266..3956b523 100644 --- a/src/constants/themes/index.ts +++ b/src/constants/themes/index.ts @@ -1,7 +1,6 @@ export enum Theme { Default = 'Default', Horizon = 'Horizon', - Sansevieria = 'Sansevieria', } interface ThemeColors { @@ -18,7 +17,7 @@ export const themeColors: Record = { 'linear-gradient(165deg, #ff7549 -50%, #ff3344 150%)', 'linear-gradient(170deg, #582cd0, #592071)', ], - background: "url('/images/noise_top.png') 0% 0% #23201f", + background: 'url(\'/images/noise_top.png\') 0% 0% #23201f', }, [Theme.Horizon]: { name: 'Веспера', @@ -29,13 +28,4 @@ export const themeColors: Record = { ], background: 'url("/images/horizon_bg.svg") 50% 50% / cover rgb(28, 30, 38)', }, - [Theme.Sansevieria]: { - name: 'Сансевирия', - colors: [ - 'linear-gradient(165deg, #f4e7aa -50%, #a23500 150%)', - 'linear-gradient(165deg, #ff7e56 -50%, #280003 150%)', - 'linear-gradient(170deg, #476695, #22252d)', - ], - background: '#1f2625', - }, }; diff --git a/src/constants/urls.ts b/src/constants/urls.ts index 9bed6e30..50da82fe 100644 --- a/src/constants/urls.ts +++ b/src/constants/urls.ts @@ -37,7 +37,7 @@ export const imagePresets = { flow_horizontal: 'flow_horizontal', } as const; -export type ImagePreset = (typeof imagePresets)[keyof typeof imagePresets]; +export type ImagePreset = typeof imagePresets[keyof typeof imagePresets]; export const imageSrcSets: Partial> = { [imagePresets[1600]]: 1600, @@ -49,7 +49,7 @@ export const imageSrcSets: Partial> = { export const flowDisplayToPreset: Record< FlowDisplayVariant, - (typeof imagePresets)[keyof typeof imagePresets] + typeof imagePresets[keyof typeof imagePresets] > = { single: 'flow_square', quadro: 'flow_square', diff --git a/src/containers/boris/BorisSuperpowers/ssr.tsx b/src/containers/boris/BorisSuperpowers/ssr.tsx index 5779c5c2..c8104207 100644 --- a/src/containers/boris/BorisSuperpowers/ssr.tsx +++ b/src/containers/boris/BorisSuperpowers/ssr.tsx @@ -3,12 +3,10 @@ import dynamic from 'next/dynamic'; import type { BorisSuperpowersProps } from './index'; export const BorisSuperPowersSSR = dynamic( - () => - import('~/containers/boris/BorisSuperpowers/index').then( - (it) => it.BorisSuperpowers, - ), + () => import('~/containers/boris/BorisSuperpowers/index') + .then(it => it.BorisSuperpowers), { ssr: false, loading: () =>
, - }, + } ); diff --git a/src/containers/dialogs/EditorCreateDialog/index.tsx b/src/containers/dialogs/EditorCreateDialog/index.tsx index 5abd35aa..50b16dd4 100644 --- a/src/containers/dialogs/EditorCreateDialog/index.tsx +++ b/src/containers/dialogs/EditorCreateDialog/index.tsx @@ -8,7 +8,7 @@ import { DialogComponentProps } from '~/types/modal'; import { values } from '~/utils/ramda'; export interface EditorCreateDialogProps extends DialogComponentProps { - type: (typeof NODE_TYPES)[keyof typeof NODE_TYPES]; + type: typeof NODE_TYPES[keyof typeof NODE_TYPES]; isInLab: boolean; } diff --git a/src/containers/dialogs/EditorDialog/constants/index.ts b/src/containers/dialogs/EditorDialog/constants/index.ts index ce392b50..dd9d0bc0 100644 --- a/src/containers/dialogs/EditorDialog/constants/index.ts +++ b/src/containers/dialogs/EditorDialog/constants/index.ts @@ -11,7 +11,7 @@ import { TextEditor } from '../components/TextEditor'; import { VideoEditor } from '../components/VideoEditor'; export const NODE_EDITORS: Record< - (typeof NODE_TYPES)[keyof typeof NODE_TYPES], + typeof NODE_TYPES[keyof typeof NODE_TYPES], FC > = { [NODE_TYPES.IMAGE]: ImageEditor, @@ -22,7 +22,7 @@ export const NODE_EDITORS: Record< }; export const NODE_EDITOR_DATA: Record< - (typeof NODE_TYPES)[keyof typeof NODE_TYPES], + typeof NODE_TYPES[keyof typeof NODE_TYPES], Partial > = { [NODE_TYPES.TEXT]: { diff --git a/src/containers/dialogs/Modal/index.tsx b/src/containers/dialogs/Modal/index.tsx index 090a7a6a..7bda9a70 100644 --- a/src/containers/dialogs/Modal/index.tsx +++ b/src/containers/dialogs/Modal/index.tsx @@ -1,8 +1,7 @@ -import { FC, createElement, Suspense } from 'react'; +import { FC, createElement } from 'react'; import { observer } from 'mobx-react-lite'; -import { LoaderCircle } from '~/components/common/LoaderCircle'; import { ModalWrapper } from '~/components/common/ModalWrapper'; import { DIALOG_CONTENT } from '~/constants/modal'; import { useModalStore } from '~/store/modal/useModalStore'; @@ -19,12 +18,10 @@ const Modal: FC = observer(() => { return ( - }> - {createElement(DIALOG_CONTENT[current!]! as any, { - onRequestClose: hide, - ...props, - })} - + {createElement(DIALOG_CONTENT[current!]! as any, { + onRequestClose: hide, + ...props, + })} ); }); diff --git a/src/containers/dialogs/PhotoSwipe/index.tsx b/src/containers/dialogs/PhotoSwipe/index.tsx index 0872b2cc..3a285696 100644 --- a/src/containers/dialogs/PhotoSwipe/index.tsx +++ b/src/containers/dialogs/PhotoSwipe/index.tsx @@ -1,12 +1,10 @@ -import { useEffect, useRef } from 'react'; - -import 'photoswipe/style.css'; +import { useEffect, useRef, VFC } from 'react'; +import classNames from 'classnames'; import { observer } from 'mobx-react-lite'; -import PSWP from 'photoswipe'; -import { renderToStaticMarkup } from 'react-dom/server'; +import PhotoSwipeUI_Default from 'photoswipe/dist/photoswipe-ui-default.js'; +import PhotoSwipeJs from 'photoswipe/dist/photoswipe.js'; -import { Icon } from '~/components/common/Icon'; import { imagePresets } from '~/constants/urls'; import { useWindowSize } from '~/hooks/dom/useWindowSize'; import { useModal } from '~/hooks/modal/useModal'; @@ -15,55 +13,125 @@ import { DialogComponentProps } from '~/types/modal'; import { getURL } from '~/utils/dom'; import styles from './styles.module.scss'; -export interface Props extends DialogComponentProps { + +export interface PhotoSwipeProps extends DialogComponentProps { items: IFile[]; index: number; } -const arrowNextSVG = renderToStaticMarkup(); -const arrowPrevSVG = renderToStaticMarkup(); -const closeSVG = renderToStaticMarkup(); - -const padding = { top: 10, left: 10, right: 10, bottom: 10 } as const; - -const PhotoSwipe = observer(({ index, items }: Props) => { +const PhotoSwipe: VFC = observer(({ index, items }) => { + let ref = useRef(null); const { hideModal } = useModal(); const { isTablet } = useWindowSize(); - const pswp = useRef(new PSWP()); useEffect(() => { - const dataSource = items.map((file) => ({ - src: getURL(file, imagePresets[1600]), - width: file.metadata?.width, - height: file.metadata?.height, - })); + new Promise(async (resolve) => { + const images = await Promise.all( + items.map( + (file) => + new Promise((resolve) => { + const src = getURL( + file, + isTablet ? imagePresets[900] : imagePresets[1600], + ); - pswp.current.options = { - ...pswp.current.options, - dataSource, - index: index || 0, - closeOnVerticalDrag: true, - padding, - mainClass: styles.wrap, - zoom: false, - counter: false, - bgOpacity: 0.1, - arrowNextSVG, - arrowPrevSVG, - closeSVG, - }; + if (file.metadata?.width && file.metadata.height) { + resolve({ + src, + w: file.metadata.width, + h: file.metadata.height, + }); - pswp.current.on('closingAnimationEnd', hideModal); - pswp.current.init(); + return; + } - return () => { - pswp.current?.off('close', hideModal); - // eslint-disable-next-line react-hooks/exhaustive-deps - pswp.current?.destroy(); - }; + const img = new Image(); + + img.onload = () => { + resolve({ + src, + h: img.naturalHeight, + w: img.naturalWidth, + }); + }; + + img.onerror = () => { + resolve({}); + }; + + img.src = getURL(file, imagePresets[1600]); + }), + ), + ); + + resolve(images); + }).then((images) => { + const ps = new PhotoSwipeJs(ref.current, PhotoSwipeUI_Default, images, { + index: index || 0, + closeOnScroll: false, + history: false, + }); + + ps.init(); + ps.listen('destroy', hideModal); + ps.listen('close', hideModal); + }); }, [hideModal, items, index, isTablet]); - return null; + return ( +