ui: embed player, some pdf fixes for kai
This commit is contained in:
parent
3c249b2b5a
commit
256b049e7d
23 changed files with 377 additions and 51 deletions
|
|
@ -5,6 +5,7 @@ import Ideas from './Ideas';
|
|||
import { Loader } from 'UI';
|
||||
import { kaiStore } from '../KaiStore';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import EmbedPlayer from './EmbedPlayer';
|
||||
|
||||
function ChatLog({
|
||||
projectId,
|
||||
|
|
@ -21,6 +22,7 @@ function ChatLog({
|
|||
chatTitle: string | null;
|
||||
onCancel: () => void;
|
||||
}) {
|
||||
const [embedSession, setEmbedSession] = React.useState<any>(null);
|
||||
const messages = kaiStore.messages;
|
||||
const loading = kaiStore.loadingChat;
|
||||
const chatRef = React.useRef<HTMLDivElement>(null);
|
||||
|
|
@ -64,6 +66,12 @@ function ChatLog({
|
|||
'overflow-y-auto relative flex flex-col items-center justify-between w-full h-full pt-4'
|
||||
}
|
||||
>
|
||||
{embedSession ? (
|
||||
<EmbedPlayer
|
||||
session={embedSession}
|
||||
onClose={() => setEmbedSession(null)}
|
||||
/>
|
||||
) : null}
|
||||
<div className={'flex flex-col gap-2 w-2/3 min-h-max'}>
|
||||
{messages.map((msg, index) => (
|
||||
<React.Fragment key={msg.messageId ?? index}>
|
||||
|
|
@ -71,6 +79,7 @@ function ChatLog({
|
|||
siteId={projectId}
|
||||
message={msg}
|
||||
chatTitle={chatTitle}
|
||||
onReplay={(session) => setEmbedSession(session)}
|
||||
canEdit={
|
||||
processingStage === null &&
|
||||
msg.isUser &&
|
||||
|
|
|
|||
|
|
@ -27,12 +27,14 @@ function ChatMsg({
|
|||
canEdit,
|
||||
message,
|
||||
chatTitle,
|
||||
onReplay,
|
||||
}: {
|
||||
message: Message;
|
||||
userName?: string;
|
||||
canEdit?: boolean;
|
||||
siteId: string;
|
||||
chatTitle: string | null;
|
||||
onReplay: (session: any) => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [metric, setMetric] = React.useState<Widget | null>(null);
|
||||
|
|
@ -73,7 +75,6 @@ function ChatMsg({
|
|||
.then(async ({ jsPDF }) => {
|
||||
const doc = new jsPDF();
|
||||
const blockWidth = 170; // mm
|
||||
doc.addImage('/assets/img/logo-img.png', 20, 15, 30, 5);
|
||||
const content = bodyRef.current!.cloneNode(true) as HTMLElement;
|
||||
if (userPrompt) {
|
||||
const titleHeader = document.createElement('h2');
|
||||
|
|
@ -81,6 +82,18 @@ function ChatMsg({
|
|||
titleHeader.style.marginBottom = '10px';
|
||||
content.prepend(titleHeader);
|
||||
}
|
||||
// insert logo /assets/img/logo-img.png
|
||||
const logo = new Image();
|
||||
logo.src = '/assets/img/logo-img.png';
|
||||
logo.style.width = '130px';
|
||||
const container = document.createElement('div');
|
||||
container.style.display = 'flex';
|
||||
container.style.alignItems = 'center';
|
||||
container.style.justifyContent = 'center';
|
||||
container.style.marginBottom = '10mm';
|
||||
container.style.width = `${blockWidth}mm`;
|
||||
container.appendChild(logo);
|
||||
content.prepend(container);
|
||||
content.querySelectorAll('ul').forEach((ul) => {
|
||||
const frag = document.createDocumentFragment();
|
||||
ul.querySelectorAll('li').forEach((li) => {
|
||||
|
|
@ -123,9 +136,9 @@ function ChatMsg({
|
|||
doc.save((chatTitle ?? 'document') + '.pdf');
|
||||
},
|
||||
// top, bottom, ?, left
|
||||
margin: [5, 10, 20, 20],
|
||||
margin: [10, 10, 20, 20],
|
||||
x: 0,
|
||||
y: 15,
|
||||
y: 0,
|
||||
// Target width
|
||||
width: blockWidth,
|
||||
// Window width for rendering
|
||||
|
|
@ -172,7 +185,7 @@ function ChatMsg({
|
|||
}, [metricData, chart_data]);
|
||||
return (
|
||||
<div className={cn('flex gap-2', isUser ? 'flex-row-reverse' : 'flex-row')}>
|
||||
<div className={'mt-1 flex flex-col group/actions max-w-[880px]'}>
|
||||
<div className={'mt-1 flex flex-col group/actions max-w-[60svw]'}>
|
||||
<div
|
||||
className={cn(
|
||||
'markdown-body',
|
||||
|
|
@ -195,8 +208,18 @@ function ChatMsg({
|
|||
{message.sessions ? (
|
||||
<div className="flex flex-col">
|
||||
{message.sessions.map((session) => (
|
||||
<div className="shadow border rounded-xl overflow-hidden mb-2">
|
||||
<SessionItem key={session.sessionId} session={session} slim />
|
||||
<div className="shadow border rounded-2xl overflow-hidden mb-2">
|
||||
<SessionItem
|
||||
disableUser
|
||||
key={session.sessionId}
|
||||
session={session}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onReplay(session);
|
||||
}}
|
||||
slim
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
75
frontend/app/components/Kai/components/EmbedPlayer.tsx
Normal file
75
frontend/app/components/Kai/components/EmbedPlayer.tsx
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import { useStore } from 'App/mstore';
|
||||
import { Loader } from 'UI';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import MobileClipsPlayer from 'App/components/Session/MobileClipsPlayer';
|
||||
import ClipsPlayer from 'App/components/Session/ClipsPlayer';
|
||||
import Session from '@/types/session/session';
|
||||
|
||||
interface Clip {
|
||||
sessionId: string | undefined;
|
||||
range: [number, number];
|
||||
message: string;
|
||||
}
|
||||
|
||||
function EmbedPlayer({
|
||||
session,
|
||||
onClose,
|
||||
}: {
|
||||
session: Session;
|
||||
onClose: () => void;
|
||||
}) {
|
||||
const { projectsStore } = useStore();
|
||||
const clip = {
|
||||
sessionId: session.sessionId,
|
||||
range: [0, session.durationMs],
|
||||
message: '',
|
||||
};
|
||||
const { isMobile } = projectsStore;
|
||||
|
||||
const onBgClick = (e: React.MouseEvent) => {
|
||||
if (e.target === e.currentTarget) {
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div
|
||||
className="w-screen h-screen fixed top-0 left-0 flex items-center justify-center"
|
||||
style={{ zIndex: 100, background: 'rgba(0,0,0, 0.15)' }}
|
||||
onClick={onBgClick}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'rounded-lg overflow-hidden',
|
||||
'rounded shadow boarder bg-white',
|
||||
)}
|
||||
style={{ width: 960 }}
|
||||
>
|
||||
{isMobile ? (
|
||||
<MobileClipsPlayer
|
||||
isHighlight
|
||||
onClose={onClose}
|
||||
clip={clip}
|
||||
currentIndex={0}
|
||||
isCurrent
|
||||
autoplay={false}
|
||||
isFull
|
||||
/>
|
||||
) : (
|
||||
<ClipsPlayer
|
||||
isHighlight
|
||||
onClose={onClose}
|
||||
clip={clip}
|
||||
currentIndex={0}
|
||||
isCurrent
|
||||
autoplay={false}
|
||||
isFull
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default observer(EmbedPlayer);
|
||||
|
|
@ -26,10 +26,11 @@ interface Props {
|
|||
autoplay: boolean;
|
||||
onClose?: () => void;
|
||||
isHighlight?: boolean;
|
||||
isFull?: boolean;
|
||||
}
|
||||
|
||||
function ClipsPlayer(props: Props) {
|
||||
const { clip, currentIndex, isCurrent, onClose, isHighlight } = props;
|
||||
const { clip, currentIndex, isCurrent, onClose, isHighlight, isFull } = props;
|
||||
const { sessionStore } = useStore();
|
||||
const { prefetched } = sessionStore;
|
||||
const [windowActive, setWindowActive] = useState(!document.hidden);
|
||||
|
|
@ -146,6 +147,7 @@ function ClipsPlayer(props: Props) {
|
|||
onClose={onClose}
|
||||
range={clip.range}
|
||||
session={session!}
|
||||
isFull={isFull}
|
||||
/>
|
||||
<ClipPlayerContent
|
||||
message={clip.message}
|
||||
|
|
@ -153,6 +155,7 @@ function ClipsPlayer(props: Props) {
|
|||
autoplay={props.autoplay}
|
||||
range={clip.range}
|
||||
session={session!}
|
||||
isFull={isFull}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -19,13 +19,14 @@ interface Props {
|
|||
isHighlight?: boolean;
|
||||
message?: string;
|
||||
isMobile?: boolean;
|
||||
isFull?: boolean;
|
||||
}
|
||||
|
||||
function ClipPlayerContent(props: Props) {
|
||||
const playerContext = React.useContext<IPlayerContext>(PlayerContext);
|
||||
const screenWrapper = React.useRef<HTMLDivElement>(null);
|
||||
const { time } = playerContext.store.get();
|
||||
const { range } = props;
|
||||
const { range, isFull } = props;
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!playerContext.player) return;
|
||||
|
|
@ -90,7 +91,7 @@ function ClipPlayerContent(props: Props) {
|
|||
<div className="leading-none font-medium">{props.message}</div>
|
||||
</div>
|
||||
) : null}
|
||||
<ClipPlayerControls session={props.session} range={props.range} />
|
||||
<ClipPlayerControls isFull={isFull} session={props.session} range={props.range} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -15,9 +15,11 @@ import { useTranslation } from 'react-i18next';
|
|||
function ClipPlayerControls({
|
||||
session,
|
||||
range,
|
||||
isFull,
|
||||
}: {
|
||||
session: Session;
|
||||
range: [number, number];
|
||||
isFull?: boolean;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { projectsStore } = useStore();
|
||||
|
|
@ -47,7 +49,7 @@ function ClipPlayerControls({
|
|||
<PlayButton state={state} togglePlay={togglePlay} iconSize={30} />
|
||||
<Timeline range={range} />
|
||||
<Button size="small" type="primary" onClick={showFullSession}>
|
||||
{t('Play Full Session')}
|
||||
{isFull ? t('Open Session') : t('Play Full Session')}
|
||||
<CirclePlay size={16} style={{ marginLeft: '0px'}} />
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -16,12 +16,13 @@ interface Props {
|
|||
range: [number, number];
|
||||
onClose?: () => void;
|
||||
isHighlight?: boolean;
|
||||
isFull?: boolean;
|
||||
}
|
||||
|
||||
function ClipPlayerHeader(props: Props) {
|
||||
const { t } = useTranslation();
|
||||
const { projectsStore } = useStore();
|
||||
const { session, range, onClose, isHighlight } = props;
|
||||
const { session, range, onClose, isHighlight, isFull } = props;
|
||||
const { siteId } = projectsStore;
|
||||
const { message } = App.useApp();
|
||||
|
||||
|
|
@ -33,7 +34,7 @@ function ClipPlayerHeader(props: Props) {
|
|||
};
|
||||
return (
|
||||
<div className="bg-white p-3 flex justify-between items-center border-b relative">
|
||||
{isHighlight ? <PartialSessionBadge /> : null}
|
||||
{isHighlight && !isFull ? <PartialSessionBadge /> : null}
|
||||
<UserCard session={props.session} />
|
||||
|
||||
<Space>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { Icon, Link } from 'UI';
|
|||
import { useStore } from 'App/mstore';
|
||||
|
||||
const PLAY_ICON_NAMES = {
|
||||
notPlayed: 'play-fill',
|
||||
notPlayed: 'play-v2',
|
||||
played: 'play-circle-light',
|
||||
} as const;
|
||||
|
||||
|
|
@ -76,10 +76,14 @@ function PlayLink(props: Props) {
|
|||
rel={props.newTab ? 'noopener noreferrer' : undefined}
|
||||
>
|
||||
<div className="group-hover:block hidden">
|
||||
<Icon name="play-hover" size={38} color={isAssist ? 'tealx' : 'teal'} />
|
||||
<Icon name={`play-fill-v2${isAssist ? '-assist' : ''}`} size={38} />
|
||||
</div>
|
||||
<div className="group-hover:hidden block">
|
||||
<Icon name={iconName} size={38} color={isAssist ? 'tealx' : 'teal'} />
|
||||
<Icon
|
||||
name={`${iconName}${isAssist ? '-assist' : ''}`}
|
||||
size={38}
|
||||
color="teal"
|
||||
/>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@ const PREFETCH_STATE = {
|
|||
|
||||
function SessionItem(props: RouteComponentProps & Props) {
|
||||
const { location } = useHistory();
|
||||
const { settingsStore, sessionStore, searchStore, searchStoreLive } = useStore();
|
||||
const { settingsStore, sessionStore, searchStore, searchStoreLive } =
|
||||
useStore();
|
||||
const { timezone, shownTimezone } = settingsStore.sessionSettings;
|
||||
const { t } = useTranslation();
|
||||
const [prefetchState, setPrefetched] = useState(PREFETCH_STATE.none);
|
||||
|
|
@ -178,7 +179,7 @@ function SessionItem(props: RouteComponentProps & Props) {
|
|||
await sessionStore.getFirstMob(sessionId);
|
||||
setPrefetched(PREFETCH_STATE.fetched);
|
||||
} catch (e) {
|
||||
setPrefetched(PREFETCH_STATE.none)
|
||||
setPrefetched(PREFETCH_STATE.none);
|
||||
console.error('Error while prefetching first mob', e);
|
||||
}
|
||||
}, [prefetchState, live, isAssist, isMobile, sessionStore, sessionId]);
|
||||
|
|
@ -247,13 +248,13 @@ function SessionItem(props: RouteComponentProps & Props) {
|
|||
);
|
||||
}, [startedAt, timezone, userTimezone]);
|
||||
|
||||
const onMetaClick = (meta: { name: string, value: string }) => {
|
||||
const onMetaClick = (meta: { name: string; value: string }) => {
|
||||
if (isAssist) {
|
||||
searchStoreLive.addFilterByKeyAndValue(meta.name, meta.value)
|
||||
searchStoreLive.addFilterByKeyAndValue(meta.name, meta.value);
|
||||
} else {
|
||||
searchStore.addFilterByKeyAndValue(meta.name, meta.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
|
|
@ -263,7 +264,11 @@ function SessionItem(props: RouteComponentProps & Props) {
|
|||
}
|
||||
>
|
||||
<div
|
||||
className={cn(stl.sessionItem, 'flex flex-col', slim ? 'px-4 py-2' : 'p-4')}
|
||||
className={cn(
|
||||
stl.sessionItem,
|
||||
'flex flex-col',
|
||||
slim ? 'px-4 py-2 text-sm' : 'p-4',
|
||||
)}
|
||||
id="session-item"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onMouseEnter={handleHover}
|
||||
|
|
@ -293,13 +298,16 @@ function SessionItem(props: RouteComponentProps & Props) {
|
|||
</div>
|
||||
<div className="overflow-hidden color-gray-medium ml-3 justify-between items-center shrink-0">
|
||||
<div
|
||||
className={cn('text-lg', {
|
||||
className={cn(
|
||||
{
|
||||
'color-teal cursor-pointer':
|
||||
!disableUser && hasUserId && !isDisabled,
|
||||
[stl.userName]:
|
||||
!disableUser && hasUserId && !isDisabled,
|
||||
'color-gray-medium': disableUser || !hasUserId,
|
||||
})}
|
||||
},
|
||||
slim ? 'text-base' : 'text-lg',
|
||||
)}
|
||||
onClick={handleUserClick}
|
||||
>
|
||||
<TextEllipsis
|
||||
|
|
@ -310,15 +318,20 @@ function SessionItem(props: RouteComponentProps & Props) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{_metaList.length > 0 && (
|
||||
<SessionMetaList onMetaClick={onMetaClick} maxLength={3} metaList={_metaList} />
|
||||
{!slim && _metaList.length > 0 && (
|
||||
<SessionMetaList
|
||||
onMetaClick={onMetaClick}
|
||||
maxLength={3}
|
||||
metaList={_metaList}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={cn(
|
||||
'px-2 flex flex-col justify-between gap-2 mt-3 lg:mt-0',
|
||||
'px-2 flex flex-col justify-between lg:mt-0',
|
||||
compact ? 'w-[40%]' : 'lg:w-1/5',
|
||||
slim ? 'gap-1 mt-1' : 'gap-2 mt-3',
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
|
|
@ -355,9 +368,12 @@ function SessionItem(props: RouteComponentProps & Props) {
|
|||
</div>
|
||||
<div
|
||||
style={{ width: '30%' }}
|
||||
className="px-2 flex flex-col justify-between gap-2"
|
||||
className={cn(
|
||||
'px-2 flex flex-col justify-between',
|
||||
slim ? 'gap-1' : 'gap-2',
|
||||
)}
|
||||
>
|
||||
<div style={{ height: '21px' }}>
|
||||
<div style={{ height: slim ? undefined : '21px' }}>
|
||||
<CountryFlag
|
||||
userCity={userCity}
|
||||
userState={userState}
|
||||
|
|
@ -454,7 +470,9 @@ function SessionItem(props: RouteComponentProps & Props) {
|
|||
onClick={onClick}
|
||||
queryParams={queryParams}
|
||||
query={query}
|
||||
beforeOpen={live || isAssist ? undefined : populateData}
|
||||
beforeOpen={
|
||||
slim || live || isAssist ? undefined : populateData
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -416,9 +416,14 @@ export { default as Play_circle_bold } from './play_circle_bold';
|
|||
export { default as Play_circle_light } from './play_circle_light';
|
||||
export { default as Play_circle } from './play_circle';
|
||||
export { default as Play_fill_new } from './play_fill_new';
|
||||
export { default as Play_fill_v2_assist } from './play_fill_v2_assist';
|
||||
export { default as Play_fill_v2 } from './play_fill_v2';
|
||||
export { default as Play_fill } from './play_fill';
|
||||
export { default as Play_hover } from './play_hover';
|
||||
export { default as Play_v2_assist } from './play_v2_assist';
|
||||
export { default as Play_v2 } from './play_v2';
|
||||
export { default as Play } from './play';
|
||||
export { default as Played_v2 } from './played_v2';
|
||||
export { default as Plug } from './plug';
|
||||
export { default as Plus_circle } from './plus_circle';
|
||||
export { default as Plus } from './plus';
|
||||
|
|
|
|||
18
frontend/app/components/ui/Icons/play_fill_v2.tsx
Normal file
18
frontend/app/components/ui/Icons/play_fill_v2.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* Auto-generated, do not edit */
|
||||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
size?: number | string;
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
fill?: string;
|
||||
}
|
||||
|
||||
function Play_fill_v2(props: Props) {
|
||||
const { size = 14, width = size, height = size, fill = '' } = props;
|
||||
return (
|
||||
<svg viewBox="0 0 37 36" fill="none" width={ `${ width }px` } height={ `${ height }px` } ><rect x=".663" width="36" height="36" rx="18" fill="#394DFE"/><path d="M24.851 16.358a2 2 0 0 1 0 3.284l-7.323 5.09c-1.326.922-3.141-.027-3.141-1.642V12.91c0-1.615 1.815-2.564 3.141-1.643l7.323 5.09Z" fill="#E2E4FD"/></svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default Play_fill_v2;
|
||||
18
frontend/app/components/ui/Icons/play_fill_v2_assist.tsx
Normal file
18
frontend/app/components/ui/Icons/play_fill_v2_assist.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* Auto-generated, do not edit */
|
||||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
size?: number | string;
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
fill?: string;
|
||||
}
|
||||
|
||||
function Play_fill_v2_assist(props: Props) {
|
||||
const { size = 14, width = size, height = size, fill = '' } = props;
|
||||
return (
|
||||
<svg viewBox="0 0 37 36" fill="none" width={ `${ width }px` } height={ `${ height }px` } ><rect x=".663" width="36" height="36" rx="18" fill="#3EAAAF"/><path d="M24.851 16.358a2 2 0 0 1 0 3.284l-7.323 5.09c-1.326.922-3.141-.027-3.141-1.642V12.91c0-1.615 1.815-2.564 3.141-1.643l7.323 5.09Z" fill="#E2E4FD"/></svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default Play_fill_v2_assist;
|
||||
18
frontend/app/components/ui/Icons/play_v2.tsx
Normal file
18
frontend/app/components/ui/Icons/play_v2.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* Auto-generated, do not edit */
|
||||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
size?: number | string;
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
fill?: string;
|
||||
}
|
||||
|
||||
function Play_v2(props: Props) {
|
||||
const { size = 14, width = size, height = size, fill = '' } = props;
|
||||
return (
|
||||
<svg viewBox="0 0 37 36" fill="none" width={ `${ width }px` } height={ `${ height }px` } ><rect x=".663" width="36" height="36" rx="18" fill="#E2E4FD"/><path d="M24.851 16.358a2 2 0 0 1 0 3.284l-7.323 5.09c-1.326.922-3.141-.027-3.141-1.642V12.91c0-1.615 1.815-2.564 3.141-1.643l7.323 5.09Z" fill="#394DFE"/></svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default Play_v2;
|
||||
18
frontend/app/components/ui/Icons/play_v2_assist.tsx
Normal file
18
frontend/app/components/ui/Icons/play_v2_assist.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* Auto-generated, do not edit */
|
||||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
size?: number | string;
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
fill?: string;
|
||||
}
|
||||
|
||||
function Play_v2_assist(props: Props) {
|
||||
const { size = 14, width = size, height = size, fill = '' } = props;
|
||||
return (
|
||||
<svg viewBox="0 0 37 36" fill="none" width={ `${ width }px` } height={ `${ height }px` } ><rect x=".663" width="36" height="36" rx="18" fill="#E2E4FD"/><path d="M24.851 16.358a2 2 0 0 1 0 3.284l-7.323 5.09c-1.326.922-3.141-.027-3.141-1.642V12.91c0-1.615 1.815-2.564 3.141-1.643l7.323 5.09Z" fill="#3EAAAF"/></svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default Play_v2_assist;
|
||||
18
frontend/app/components/ui/Icons/played_v2.tsx
Normal file
18
frontend/app/components/ui/Icons/played_v2.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* Auto-generated, do not edit */
|
||||
import React from 'react';
|
||||
|
||||
interface Props {
|
||||
size?: number | string;
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
fill?: string;
|
||||
}
|
||||
|
||||
function Played_v2(props: Props) {
|
||||
const { size = 14, width = size, height = size, fill = '' } = props;
|
||||
return (
|
||||
<svg viewBox="0 0 37 36" fill="none" width={ `${ width }px` } height={ `${ height }px` } ><rect x=".663" width="36" height="36" rx="18" fill="#E2E4FD"/><path d="M24.851 16.358a2 2 0 0 1 0 3.284l-7.323 5.09c-1.326.922-3.141-.027-3.141-1.642V12.91c0-1.615 1.815-2.564 3.141-1.643l7.323 5.09Z" fill="#fff"/></svg>
|
||||
);
|
||||
}
|
||||
|
||||
export default Played_v2;
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -29,6 +29,7 @@ import {
|
|||
spotOnlyCats,
|
||||
} from './data';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { tag } from '@/components/Session_/Inspector/inspector.css';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
|
|
@ -104,7 +105,7 @@ function SideMenu(props: Props) {
|
|||
modules.includes(MODULES.USABILITY_TESTS),
|
||||
item.isAdmin && !isAdmin,
|
||||
item.isEnterprise && !isEnterprise,
|
||||
item.key === MENU.KAI && !hasAi
|
||||
item.key === MENU.KAI && !hasAi,
|
||||
].some((cond) => cond);
|
||||
|
||||
return { ...item, hidden: isHidden };
|
||||
|
|
@ -118,7 +119,15 @@ function SideMenu(props: Props) {
|
|||
hidden: allItemsHidden,
|
||||
};
|
||||
});
|
||||
}, [isAdmin, isEnterprise, isPreferencesActive, modules, spotOnly, siteId, i18n.language]);
|
||||
}, [
|
||||
isAdmin,
|
||||
isEnterprise,
|
||||
isPreferencesActive,
|
||||
modules,
|
||||
spotOnly,
|
||||
siteId,
|
||||
i18n.language,
|
||||
]);
|
||||
|
||||
const menuRoutes: any = {
|
||||
[MENU.EXIT]: () =>
|
||||
|
|
@ -216,7 +225,10 @@ function SideMenu(props: Props) {
|
|||
color={isActive ? 'teal' : 'black'}
|
||||
/>
|
||||
}
|
||||
className={cn('!rounded-lg hover-fill-teal', isActive ? 'color-main' : 'color-black')}
|
||||
className={cn(
|
||||
'!rounded-lg hover-fill-teal',
|
||||
isActive ? 'color-main' : 'color-black',
|
||||
)}
|
||||
>
|
||||
{item.label}
|
||||
</Menu.Item>
|
||||
|
|
@ -235,7 +247,10 @@ function SideMenu(props: Props) {
|
|||
/>
|
||||
}
|
||||
style={{ paddingLeft: '20px' }}
|
||||
className={cn('!rounded-lg !pe-0', isActive ? 'color-main' : 'color-black')}
|
||||
className={cn(
|
||||
'!rounded-lg !pe-0',
|
||||
isActive ? 'color-main' : 'color-black',
|
||||
)}
|
||||
itemIcon={
|
||||
item.leading ? (
|
||||
<Icon
|
||||
|
|
@ -255,13 +270,6 @@ function SideMenu(props: Props) {
|
|||
}}
|
||||
>
|
||||
{item.label}
|
||||
<Tag
|
||||
color="cyan"
|
||||
bordered={false}
|
||||
className="text-xs ml-2"
|
||||
>
|
||||
{t('Beta')}
|
||||
</Tag>
|
||||
</div>
|
||||
</Menu.Item>
|
||||
);
|
||||
|
|
@ -285,7 +293,20 @@ function SideMenu(props: Props) {
|
|||
})}
|
||||
key={child.key}
|
||||
>
|
||||
{child.label}
|
||||
<div className="flex items-center justify-between">
|
||||
<span>{child.label}</span>
|
||||
{child.tag ? (
|
||||
<div className="ml-auto">
|
||||
<Tag
|
||||
color={child.tag.color}
|
||||
bordered={child.tag.border}
|
||||
className="text-xs ml-2"
|
||||
>
|
||||
{child.tag.label}
|
||||
</Tag>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.SubMenu>
|
||||
|
|
@ -301,7 +322,10 @@ function SideMenu(props: Props) {
|
|||
/>
|
||||
}
|
||||
style={{ paddingLeft: '20px' }}
|
||||
className={cn('!rounded-lg hover-fill-teal', isActive ? 'color-main' : 'color-black')}
|
||||
className={cn(
|
||||
'!rounded-lg hover-fill-teal',
|
||||
isActive ? 'color-main' : 'color-black',
|
||||
)}
|
||||
itemIcon={
|
||||
item.leading ? (
|
||||
<Icon
|
||||
|
|
@ -312,7 +336,20 @@ function SideMenu(props: Props) {
|
|||
) : null
|
||||
}
|
||||
>
|
||||
{item.label}
|
||||
<div className="flex items-center justify-between">
|
||||
<span>{item.label}</span>
|
||||
{item.tag ? (
|
||||
<div className="ml-auto">
|
||||
<Tag
|
||||
color={item.tag.color}
|
||||
bordered={item.tag.border}
|
||||
className="text-xs ml-2"
|
||||
>
|
||||
{item.tag.label}
|
||||
</Tag>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { TFunction } from 'i18next';
|
||||
import { IconNames } from "../components/ui/SVG";
|
||||
import { IconNames } from '../components/ui/SVG';
|
||||
import React from 'react';
|
||||
|
||||
export interface MenuItem {
|
||||
|
|
@ -99,7 +99,15 @@ export const categories: (t: TFunction) => Category[] = (t) => [
|
|||
title: '',
|
||||
key: 'kai',
|
||||
items: [
|
||||
{ label: t('Kai'), key: MENU.KAI, icon: 'kai' },
|
||||
{
|
||||
label: t('Kai'),
|
||||
key: MENU.KAI,
|
||||
icon: 'kai-mono',
|
||||
tag: {
|
||||
label: t('New'),
|
||||
color: '#394DFE',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
|||
6
frontend/app/svg/icons/play-fill-v2-assist.svg
Normal file
6
frontend/app/svg/icons/play-fill-v2-assist.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<svg viewBox="0 0 37 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0.662598" width="36" height="36" rx="18" fill="#3EAAAF" />
|
||||
<path
|
||||
d="M24.8513 16.3578C25.9959 17.1534 25.9959 18.8466 24.8513 19.6422L17.5283 24.7325C16.2022 25.6543 14.3868 24.7053 14.3868 23.0902L14.3868 12.9098C14.3868 11.2947 16.2022 10.3457 17.5283 11.2675L24.8513 16.3578Z"
|
||||
fill="#E2E4FD" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 398 B |
6
frontend/app/svg/icons/play-fill-v2.svg
Normal file
6
frontend/app/svg/icons/play-fill-v2.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<svg viewBox="0 0 37 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0.662598" width="36" height="36" rx="18" fill="#394DFE" />
|
||||
<path
|
||||
d="M24.8513 16.3578C25.9959 17.1534 25.9959 18.8466 24.8513 19.6422L17.5283 24.7325C16.2022 25.6543 14.3868 24.7053 14.3868 23.0902L14.3868 12.9098C14.3868 11.2947 16.2022 10.3457 17.5283 11.2675L24.8513 16.3578Z"
|
||||
fill="#E2E4FD" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 398 B |
6
frontend/app/svg/icons/play-v2-assist.svg
Normal file
6
frontend/app/svg/icons/play-v2-assist.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<svg viewBox="0 0 37 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0.662598" width="36" height="36" rx="18" fill="#E2E4FD" />
|
||||
<path
|
||||
d="M24.8513 16.3578C25.9959 17.1534 25.9959 18.8466 24.8513 19.6422L17.5283 24.7325C16.2022 25.6543 14.3868 24.7053 14.3868 23.0902L14.3868 12.9098C14.3868 11.2947 16.2022 10.3457 17.5283 11.2675L24.8513 16.3578Z"
|
||||
fill="#3EAAAF" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 398 B |
6
frontend/app/svg/icons/play-v2.svg
Normal file
6
frontend/app/svg/icons/play-v2.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<svg viewBox="0 0 37 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0.662598" width="36" height="36" rx="18" fill="#E2E4FD" />
|
||||
<path
|
||||
d="M24.8513 16.3578C25.9959 17.1534 25.9959 18.8466 24.8513 19.6422L17.5283 24.7325C16.2022 25.6543 14.3868 24.7053 14.3868 23.0902L14.3868 12.9098C14.3868 11.2947 16.2022 10.3457 17.5283 11.2675L24.8513 16.3578Z"
|
||||
fill="#394DFE" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 398 B |
6
frontend/app/svg/icons/played-v2.svg
Normal file
6
frontend/app/svg/icons/played-v2.svg
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<svg viewBox="0 0 37 36" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0.662598" width="36" height="36" rx="18" fill="#E2E4FD" />
|
||||
<path
|
||||
d="M24.8513 16.3578C25.9959 17.1534 25.9959 18.8466 24.8513 19.6422L17.5283 24.7325C16.2022 25.6543 14.3868 24.7053 14.3868 23.0902L14.3868 12.9098C14.3868 11.2947 16.2022 10.3457 17.5283 11.2675L24.8513 16.3578Z"
|
||||
fill="white" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 396 B |
Loading…
Add table
Reference in a new issue