mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-08-14 12:50:37 +03:00
F: Rework video embedding. Add VK Video
This commit is contained in:
parent
bd6f72aceb
commit
2ecdbd1719
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -177,6 +177,7 @@
|
||||||
"Upvote",
|
"Upvote",
|
||||||
"Viewset",
|
"Viewset",
|
||||||
"viewsets",
|
"viewsets",
|
||||||
|
"vkvideo",
|
||||||
"wordform",
|
"wordform",
|
||||||
"Wordforms",
|
"Wordforms",
|
||||||
"XCSDATN",
|
"XCSDATN",
|
||||||
|
|
|
@ -4,6 +4,9 @@ import React from 'react';
|
||||||
|
|
||||||
import { DialogType, useDialogsStore } from '@/stores/dialogs';
|
import { DialogType, useDialogsStore } from '@/stores/dialogs';
|
||||||
|
|
||||||
|
const DlgShowVideo = React.lazy(() =>
|
||||||
|
import('@/features/help/dialogs/dlg-show-video').then(module => ({ default: module.DlgShowVideo }))
|
||||||
|
);
|
||||||
const DlgChangeInputSchema = React.lazy(() =>
|
const DlgChangeInputSchema = React.lazy(() =>
|
||||||
import('@/features/oss/dialogs/dlg-change-input-schema').then(module => ({ default: module.DlgChangeInputSchema }))
|
import('@/features/oss/dialogs/dlg-change-input-schema').then(module => ({ default: module.DlgChangeInputSchema }))
|
||||||
);
|
);
|
||||||
|
@ -161,6 +164,8 @@ export const GlobalDialogs = () => {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
switch (active) {
|
switch (active) {
|
||||||
|
case DialogType.SHOW_VIDEO:
|
||||||
|
return <DlgShowVideo />;
|
||||||
case DialogType.CONSTITUENTA_TEMPLATE:
|
case DialogType.CONSTITUENTA_TEMPLATE:
|
||||||
return <DlgCstTemplate />;
|
return <DlgCstTemplate />;
|
||||||
case DialogType.CREATE_CONSTITUENTA:
|
case DialogType.CREATE_CONSTITUENTA:
|
||||||
|
|
|
@ -39,6 +39,7 @@ export { RiMenuFoldFill as IconMenuFold } from 'react-icons/ri';
|
||||||
export { RiMenuUnfoldFill as IconMenuUnfold } from 'react-icons/ri';
|
export { RiMenuUnfoldFill as IconMenuUnfold } from 'react-icons/ri';
|
||||||
export { LuMoon as IconDarkTheme } from 'react-icons/lu';
|
export { LuMoon as IconDarkTheme } from 'react-icons/lu';
|
||||||
export { LuSun as IconLightTheme } from 'react-icons/lu';
|
export { LuSun as IconLightTheme } from 'react-icons/lu';
|
||||||
|
export { IoVideocamOutline as IconVideo } from 'react-icons/io5';
|
||||||
export { LuFolderTree as IconFolderTree } from 'react-icons/lu';
|
export { LuFolderTree as IconFolderTree } from 'react-icons/lu';
|
||||||
export { LuFolder as IconFolder } from 'react-icons/lu';
|
export { LuFolder as IconFolder } from 'react-icons/lu';
|
||||||
export { LuFolderSearch as IconFolderSearch } from 'react-icons/lu';
|
export { LuFolderSearch as IconFolderSearch } from 'react-icons/lu';
|
||||||
|
|
42
rsconcept/frontend/src/components/view/embed-vkvideo.tsx
Normal file
42
rsconcept/frontend/src/components/view/embed-vkvideo.tsx
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
interface EmbedVKVideoProps {
|
||||||
|
/** Video ID to embed. */
|
||||||
|
videoID: string;
|
||||||
|
|
||||||
|
/** Display height in pixels. */
|
||||||
|
pxHeight: number;
|
||||||
|
|
||||||
|
/** Display width in pixels. */
|
||||||
|
pxWidth?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Embeds a YouTube video into the page using the given video ID and dimensions.
|
||||||
|
*/
|
||||||
|
export function EmbedVKVideo({ videoID, pxHeight, pxWidth }: EmbedVKVideoProps) {
|
||||||
|
if (!pxWidth) {
|
||||||
|
pxWidth = (pxHeight * 16) / 9;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className='relative h-0 mt-1'
|
||||||
|
style={{
|
||||||
|
paddingBottom: `${pxHeight}px`,
|
||||||
|
paddingLeft: `${pxWidth}px`
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<iframe
|
||||||
|
allowFullScreen
|
||||||
|
title='Встроенное видео ВКонтакте'
|
||||||
|
allow='autoplay; encrypted-media; fullscreen; picture-in-picture; screen-wake-lock;'
|
||||||
|
className='absolute top-0 left-0 border'
|
||||||
|
style={{
|
||||||
|
minHeight: `${pxHeight}px`,
|
||||||
|
minWidth: `${pxWidth}px`
|
||||||
|
}}
|
||||||
|
width={`${pxWidth}px`}
|
||||||
|
height={`${pxHeight}px`}
|
||||||
|
src={`https://vk.com/video_ext.php?${videoID}&hd=1`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { IconVideo } from '@/components/icons';
|
||||||
|
import { type Styling } from '@/components/props';
|
||||||
|
import { cn } from '@/components/utils';
|
||||||
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
import { globalIDs, type IVideo } from '@/utils/constants';
|
||||||
|
|
||||||
|
interface BadgeVideoProps extends Styling {
|
||||||
|
video: IVideo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Displays a badge with a video icon to click and open the video. */
|
||||||
|
export function BadgeVideo({ video, className, ...restProps }: BadgeVideoProps) {
|
||||||
|
const showVideo = useDialogsStore(state => state.showVideo);
|
||||||
|
|
||||||
|
function handleShowExplication() {
|
||||||
|
showVideo({ video: video });
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IconVideo
|
||||||
|
className={cn('cursor-pointer', className)}
|
||||||
|
onClick={handleShowExplication}
|
||||||
|
data-tooltip-id={globalIDs.tooltip}
|
||||||
|
data-tooltip-content='Просмотр видео'
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
|
|
||||||
|
import { ModalView } from '@/components/modal';
|
||||||
|
import { TabLabel } from '@/components/tabs';
|
||||||
|
import { useWindowSize } from '@/hooks/use-window-size';
|
||||||
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
import { usePreferencesStore } from '@/stores/preferences';
|
||||||
|
import { type IVideo } from '@/utils/constants';
|
||||||
|
|
||||||
|
import { TabVK } from './tab-vk';
|
||||||
|
import { TabYoutube } from './tab-youtube';
|
||||||
|
|
||||||
|
export const TabID = {
|
||||||
|
VK: 0,
|
||||||
|
YOUTUBE: 1
|
||||||
|
} as const;
|
||||||
|
export type TabID = (typeof TabID)[keyof typeof TabID];
|
||||||
|
|
||||||
|
export interface DlgShowVideoProps {
|
||||||
|
video: IVideo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DlgShowVideo() {
|
||||||
|
const preferredPlayer = usePreferencesStore(state => state.preferredPlayer);
|
||||||
|
const setPreferredPlayer = usePreferencesStore(state => state.setPreferredPlayer);
|
||||||
|
const activeTab = preferredPlayer === 'vk' ? TabID.VK : TabID.YOUTUBE;
|
||||||
|
const { video } = useDialogsStore(state => state.props as DlgShowVideoProps);
|
||||||
|
const windowSize = useWindowSize();
|
||||||
|
|
||||||
|
const videoHeight = (() => {
|
||||||
|
const viewH = windowSize.height ?? 0;
|
||||||
|
const viewW = windowSize.width ?? 0;
|
||||||
|
const availableWidth = viewW - 80;
|
||||||
|
return Math.min(Math.max(viewH - 150, 300), Math.floor((availableWidth * 9) / 16));
|
||||||
|
})();
|
||||||
|
|
||||||
|
function setActiveTab(newTab: TabID) {
|
||||||
|
setPreferredPlayer(newTab === TabID.VK ? 'vk' : 'youtube');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalView fullScreen className='relative w-[calc(100dvw-3rem)] h-[calc(100dvh-3rem)]'>
|
||||||
|
<Tabs
|
||||||
|
className='flex flex-col gap-1 items-center pt-3'
|
||||||
|
selectedIndex={activeTab}
|
||||||
|
onSelect={index => setActiveTab(index as TabID)}
|
||||||
|
>
|
||||||
|
<TabList className='mx-auto flex border divide-x rounded-none'>
|
||||||
|
<TabLabel label='ВК Видео' className='w-32' />
|
||||||
|
<TabLabel label='Youtube' className='w-32' />
|
||||||
|
</TabList>
|
||||||
|
|
||||||
|
<TabPanel>
|
||||||
|
<TabVK videoHeight={videoHeight} videoID={video.vk} />
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel>
|
||||||
|
<TabYoutube videoHeight={videoHeight} videoID={video.youtube} />
|
||||||
|
</TabPanel>
|
||||||
|
</Tabs>
|
||||||
|
</ModalView>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export { DlgShowVideo as DlgShowVideo } from './dlg-show-video';
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { EmbedVKVideo } from '@/components/view/embed-vkvideo';
|
||||||
|
|
||||||
|
interface TabVKProps {
|
||||||
|
videoHeight: number;
|
||||||
|
videoID: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TabVK({ videoHeight, videoID }: TabVKProps) {
|
||||||
|
return <EmbedVKVideo videoID={videoID} pxHeight={videoHeight} />;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { EmbedYoutube } from '@/components/view';
|
||||||
|
|
||||||
|
interface TabYoutubeProps {
|
||||||
|
videoHeight: number;
|
||||||
|
videoID: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TabYoutube({ videoHeight, videoID }: TabYoutubeProps) {
|
||||||
|
return <EmbedYoutube videoID={videoID} pxHeight={videoHeight} />;
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import { TextURL } from '@/components/control';
|
import { TextURL } from '@/components/control';
|
||||||
|
import { IconVideo } from '@/components/icons';
|
||||||
import { external_urls, prefixes } from '@/utils/constants';
|
import { external_urls, prefixes } from '@/utils/constants';
|
||||||
|
|
||||||
import { LinkTopic } from '../components/link-topic';
|
import { LinkTopic } from '../components/link-topic';
|
||||||
|
@ -11,7 +12,7 @@ export function HelpMain() {
|
||||||
<h1>Портал</h1>
|
<h1>Портал</h1>
|
||||||
<p>
|
<p>
|
||||||
Портал позволяет анализировать предметные области, формально записывать системы определений и синтезировать их с
|
Портал позволяет анализировать предметные области, формально записывать системы определений и синтезировать их с
|
||||||
помощью математического аппарата <LinkTopic text='Родов структур' topic={HelpTopic.RSLANG} />
|
помощью математического аппарата <LinkTopic text='Родов структур' topic={HelpTopic.RSLANG} />.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Такие системы называются <LinkTopic text='Концептуальными схемами' topic={HelpTopic.CC_SYSTEM} /> и состоят из
|
Такие системы называются <LinkTopic text='Концептуальными схемами' topic={HelpTopic.CC_SYSTEM} /> и состоят из
|
||||||
|
@ -19,6 +20,10 @@ export function HelpMain() {
|
||||||
определения. Концептуальные схемы могут связываться путем синтеза в{' '}
|
определения. Концептуальные схемы могут связываться путем синтеза в{' '}
|
||||||
<LinkTopic text='Операционной схеме синтеза' topic={HelpTopic.CC_OSS} />.
|
<LinkTopic text='Операционной схеме синтеза' topic={HelpTopic.CC_OSS} />.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
Значок <IconVideo className='inline-icon' /> при нажатии отображает видео о различных темах и подробностях
|
||||||
|
работы Портала. Просмотр видео доступен на Youtube и ВКонтакте.
|
||||||
|
</p>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary className='text-center font-semibold'>Разделы Справки</summary>
|
<summary className='text-center font-semibold'>Разделы Справки</summary>
|
||||||
|
|
|
@ -1,21 +1,10 @@
|
||||||
import { EmbedYoutube } from '@/components/view';
|
import { external_urls, videos } from '@/utils/constants';
|
||||||
import { useWindowSize } from '@/hooks/use-window-size';
|
|
||||||
import { external_urls, youtube } from '@/utils/constants';
|
|
||||||
|
|
||||||
|
import { BadgeVideo } from '../components/badge-video';
|
||||||
import { Subtopics } from '../components/subtopics';
|
import { Subtopics } from '../components/subtopics';
|
||||||
import { HelpTopic } from '../models/help-topic';
|
import { HelpTopic } from '../models/help-topic';
|
||||||
|
|
||||||
export function HelpRSLang() {
|
export function HelpRSLang() {
|
||||||
const windowSize = useWindowSize();
|
|
||||||
const isSmall = windowSize.isSmall;
|
|
||||||
|
|
||||||
const videoHeight = (() => {
|
|
||||||
const viewH = windowSize.height ?? 0;
|
|
||||||
const viewW = windowSize.width ?? 0;
|
|
||||||
const availableWidth = viewW - (isSmall ? 35 : 310);
|
|
||||||
return Math.min(1080, Math.max(viewH - 450, 300), Math.floor((availableWidth * 9) / 16));
|
|
||||||
})();
|
|
||||||
|
|
||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col gap-4'>
|
<div className='flex flex-col gap-4'>
|
||||||
|
@ -23,14 +12,10 @@ export function HelpRSLang() {
|
||||||
<h1>Родоструктурная экспликация концептуальных схем</h1>
|
<h1>Родоструктурная экспликация концептуальных схем</h1>
|
||||||
<p>Формальная запись (<i>экспликация</i>) концептуальных схем осуществляется с помощью языка родов структур.</p>
|
<p>Формальная запись (<i>экспликация</i>) концептуальных схем осуществляется с помощью языка родов структур.</p>
|
||||||
<p>Для ознакомления с основами родов структур можно использовать следующие материалы:</p>
|
<p>Для ознакомления с основами родов структур можно использовать следующие материалы:</p>
|
||||||
<p>1. <a className='underline' href={external_urls.intro_video}>Видео: Краткое введение в мат. аппарат</a></p>
|
<p>1. <BadgeVideo className='inline-icon' video={videos.explication} /> Видео: Краткое введение в мат. аппарат</p>
|
||||||
<p>2. <a className='underline' href={external_urls.ponomarev}>Текст: Учебник И. Н. Пономарева</a></p>
|
<p>2. <a className='underline' href={external_urls.ponomarev}>Текст: Учебник И. Н. Пономарева</a></p>
|
||||||
<p>3. <a className='underline' href={external_urls.full_course}>Видео: лекции для 4 курса (второй семестр 2022-23 год)</a></p>
|
<p>3. <a className='underline' href={external_urls.full_course}>Видео: лекции для 4 курса (второй семестр 2022-23 год)</a></p>
|
||||||
</div>
|
</div>
|
||||||
<EmbedYoutube
|
|
||||||
videoID={youtube.intro}
|
|
||||||
pxHeight={videoHeight}
|
|
||||||
/>
|
|
||||||
<div className='dense'>
|
<div className='dense'>
|
||||||
<Subtopics headTopic={HelpTopic.RSLANG} />
|
<Subtopics headTopic={HelpTopic.RSLANG} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
|
|
||||||
import { type DlgCreatePromptTemplateProps } from '@/features/ai/dialogs/dlg-create-prompt-template';
|
import { type DlgCreatePromptTemplateProps } from '@/features/ai/dialogs/dlg-create-prompt-template';
|
||||||
|
import { type DlgShowVideoProps } from '@/features/help/dialogs/dlg-show-video/dlg-show-video';
|
||||||
import { type DlgChangeLocationProps } from '@/features/library/dialogs/dlg-change-location';
|
import { type DlgChangeLocationProps } from '@/features/library/dialogs/dlg-change-location';
|
||||||
import { type DlgCloneLibraryItemProps } from '@/features/library/dialogs/dlg-clone-library-item';
|
import { type DlgCloneLibraryItemProps } from '@/features/library/dialogs/dlg-clone-library-item';
|
||||||
import { type DlgCreateVersionProps } from '@/features/library/dialogs/dlg-create-version';
|
import { type DlgCreateVersionProps } from '@/features/library/dialogs/dlg-create-version';
|
||||||
|
@ -73,7 +74,9 @@ export const DialogType = {
|
||||||
IMPORT_SCHEMA: 31,
|
IMPORT_SCHEMA: 31,
|
||||||
|
|
||||||
AI_PROMPT: 32,
|
AI_PROMPT: 32,
|
||||||
CREATE_PROMPT_TEMPLATE: 33
|
CREATE_PROMPT_TEMPLATE: 33,
|
||||||
|
|
||||||
|
SHOW_VIDEO: 34
|
||||||
} as const;
|
} as const;
|
||||||
export type DialogType = (typeof DialogType)[keyof typeof DialogType];
|
export type DialogType = (typeof DialogType)[keyof typeof DialogType];
|
||||||
|
|
||||||
|
@ -86,6 +89,7 @@ interface DialogsStore {
|
||||||
props: unknown;
|
props: unknown;
|
||||||
hideDialog: () => void;
|
hideDialog: () => void;
|
||||||
|
|
||||||
|
showVideo: (props: DlgShowVideoProps) => void;
|
||||||
showCstTemplate: (props: DlgCstTemplateProps) => void;
|
showCstTemplate: (props: DlgCstTemplateProps) => void;
|
||||||
showCreateCst: (props: DlgCreateCstProps) => void;
|
showCreateCst: (props: DlgCreateCstProps) => void;
|
||||||
showCreateBlock: (props: DlgCreateBlockProps) => void;
|
showCreateBlock: (props: DlgCreateBlockProps) => void;
|
||||||
|
@ -131,6 +135,7 @@ export const useDialogsStore = create<DialogsStore>()(set => ({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showVideo: props => set({ active: DialogType.SHOW_VIDEO, props: props }),
|
||||||
showCstTemplate: props => set({ active: DialogType.CONSTITUENTA_TEMPLATE, props: props }),
|
showCstTemplate: props => set({ active: DialogType.CONSTITUENTA_TEMPLATE, props: props }),
|
||||||
showCreateCst: props => set({ active: DialogType.CREATE_CONSTITUENTA, props: props }),
|
showCreateCst: props => set({ active: DialogType.CREATE_CONSTITUENTA, props: props }),
|
||||||
showCreateOperation: props => set({ active: DialogType.CREATE_SYNTHESIS, props: props }),
|
showCreateOperation: props => set({ active: DialogType.CREATE_SYNTHESIS, props: props }),
|
||||||
|
|
|
@ -4,6 +4,11 @@ import { persist } from 'zustand/middleware';
|
||||||
|
|
||||||
import { PARAMETER } from '@/utils/constants';
|
import { PARAMETER } from '@/utils/constants';
|
||||||
|
|
||||||
|
export const videoPlayerTypes = ['vk', 'youtube'] as const;
|
||||||
|
|
||||||
|
/** Represents video player type. */
|
||||||
|
export type VideoPlayerType = (typeof videoPlayerTypes)[number];
|
||||||
|
|
||||||
interface PreferencesStore {
|
interface PreferencesStore {
|
||||||
darkMode: boolean;
|
darkMode: boolean;
|
||||||
toggleDarkMode: () => void;
|
toggleDarkMode: () => void;
|
||||||
|
@ -31,6 +36,9 @@ interface PreferencesStore {
|
||||||
|
|
||||||
showOssSidePanel: boolean;
|
showOssSidePanel: boolean;
|
||||||
toggleShowOssSidePanel: () => void;
|
toggleShowOssSidePanel: () => void;
|
||||||
|
|
||||||
|
preferredPlayer: VideoPlayerType;
|
||||||
|
setPreferredPlayer: (value: VideoPlayerType) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const usePreferencesStore = create<PreferencesStore>()(
|
export const usePreferencesStore = create<PreferencesStore>()(
|
||||||
|
@ -66,7 +74,7 @@ export const usePreferencesStore = create<PreferencesStore>()(
|
||||||
adminMode: false,
|
adminMode: false,
|
||||||
toggleAdminMode: () => set(state => ({ adminMode: !state.adminMode })),
|
toggleAdminMode: () => set(state => ({ adminMode: !state.adminMode })),
|
||||||
|
|
||||||
libraryPagination: 50,
|
libraryPagination: 20,
|
||||||
setLibraryPagination: value => set({ libraryPagination: value }),
|
setLibraryPagination: value => set({ libraryPagination: value }),
|
||||||
|
|
||||||
showCstSideList: true,
|
showCstSideList: true,
|
||||||
|
@ -82,10 +90,13 @@ export const usePreferencesStore = create<PreferencesStore>()(
|
||||||
toggleShowExpressionControls: () => set(state => ({ showExpressionControls: !state.showExpressionControls })),
|
toggleShowExpressionControls: () => set(state => ({ showExpressionControls: !state.showExpressionControls })),
|
||||||
|
|
||||||
showOssSidePanel: false,
|
showOssSidePanel: false,
|
||||||
toggleShowOssSidePanel: () => set(state => ({ showOssSidePanel: !state.showOssSidePanel }))
|
toggleShowOssSidePanel: () => set(state => ({ showOssSidePanel: !state.showOssSidePanel })),
|
||||||
|
|
||||||
|
preferredPlayer: 'vk',
|
||||||
|
setPreferredPlayer: value => set({ preferredPlayer: value })
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
version: 1,
|
version: 2,
|
||||||
name: 'portal.preferences'
|
name: 'portal.preferences'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -53,11 +53,6 @@ export const resources = {
|
||||||
db_schema: '/db_schema.svg'
|
db_schema: '/db_schema.svg'
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
/** Youtube IDs for embedding. */
|
|
||||||
export const youtube = {
|
|
||||||
intro: '0Ty9mu9sOJo'
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
/** External URLs. */
|
/** External URLs. */
|
||||||
export const external_urls = {
|
export const external_urls = {
|
||||||
concept: 'https://www.acconcept.ru/',
|
concept: 'https://www.acconcept.ru/',
|
||||||
|
@ -76,6 +71,23 @@ export const external_urls = {
|
||||||
restAPI: 'https://api.portal.acconcept.ru'
|
restAPI: 'https://api.portal.acconcept.ru'
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
/** Youtube and VK IDs for embedding. */
|
||||||
|
export interface IVideo {
|
||||||
|
/** Youtube ID. */
|
||||||
|
youtube: string;
|
||||||
|
|
||||||
|
/** VK ID. */
|
||||||
|
vk: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Youtube and VK IDs for embedding. */
|
||||||
|
export const videos = {
|
||||||
|
explication: {
|
||||||
|
youtube: '0Ty9mu9sOJo',
|
||||||
|
vk: 'oid=-232112636&id=456239017'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/** Global element ID. */
|
/** Global element ID. */
|
||||||
export const globalIDs = {
|
export const globalIDs = {
|
||||||
tooltip: 'global_tooltip',
|
tooltip: 'global_tooltip',
|
||||||
|
|
Loading…
Reference in New Issue
Block a user