functionally complete
This commit is contained in:
parent
fb3f94f36b
commit
2785991fe2
|
|
@ -23,10 +23,12 @@ export const Intro = ({
|
||||||
onJoin,
|
onJoin,
|
||||||
title,
|
title,
|
||||||
fetching = false,
|
fetching = false,
|
||||||
|
forceFetchToken = false,
|
||||||
|
forceOwner = false,
|
||||||
}) => {
|
}) => {
|
||||||
const [roomName, setRoomName] = useState();
|
const [roomName, setRoomName] = useState();
|
||||||
const [owner, setOwner] = useState(false);
|
const [fetchToken, setFetchToken] = useState(forceFetchToken);
|
||||||
const [fetchToken, setFetchToken] = useState(false);
|
const [owner, setOwner] = useState(forceOwner);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setRoomName(room);
|
setRoomName(room);
|
||||||
|
|
@ -51,10 +53,12 @@ export const Intro = ({
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
<Field label="Fetch meeting token">
|
{!forceFetchToken && (
|
||||||
<BooleanInput onChange={(e) => setFetchToken(e.target.checked)} />
|
<Field label="Fetch meeting token">
|
||||||
</Field>
|
<BooleanInput onChange={(e) => setFetchToken(e.target.checked)} />
|
||||||
{fetchToken && (
|
</Field>
|
||||||
|
)}
|
||||||
|
{fetchToken && !forceOwner && (
|
||||||
<Field label="Join as owner">
|
<Field label="Join as owner">
|
||||||
<BooleanInput onChange={(e) => setOwner(e.target.checked)} />
|
<BooleanInput onChange={(e) => setOwner(e.target.checked)} />
|
||||||
</Field>
|
</Field>
|
||||||
|
|
@ -79,6 +83,8 @@ Intro.propTypes = {
|
||||||
domain: PropTypes.string.isRequired,
|
domain: PropTypes.string.isRequired,
|
||||||
onJoin: PropTypes.func.isRequired,
|
onJoin: PropTypes.func.isRequired,
|
||||||
fetching: PropTypes.bool,
|
fetching: PropTypes.bool,
|
||||||
|
forceFetchToken: PropTypes.bool,
|
||||||
|
forceOwner: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Intro;
|
export default Intro;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { useParticipants } from '@dailyjs/shared/contexts/ParticipantsProvider';
|
import { useParticipants } from '@dailyjs/shared/contexts/ParticipantsProvider';
|
||||||
|
import { useUIState } from '@dailyjs/shared/contexts/UIStateProvider';
|
||||||
|
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
const { participantCount } = useParticipants();
|
const { participantCount } = useParticipants();
|
||||||
|
const { customCapsule } = useUIState();
|
||||||
|
|
||||||
return useMemo(
|
return useMemo(
|
||||||
() => (
|
() => (
|
||||||
|
|
@ -14,6 +16,12 @@ export const Header = () => {
|
||||||
participantCount > 1 ? 'participants' : 'participant'
|
participantCount > 1 ? 'participants' : 'participant'
|
||||||
}`}
|
}`}
|
||||||
</div>
|
</div>
|
||||||
|
{customCapsule && (
|
||||||
|
<div className={`capsule ${customCapsule.variant}`}>
|
||||||
|
{customCapsule.variant === 'recording' && <span />}
|
||||||
|
{customCapsule.label}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<style jsx>{`
|
<style jsx>{`
|
||||||
.room-header {
|
.room-header {
|
||||||
|
|
@ -31,6 +39,9 @@ export const Header = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
.capsule {
|
.capsule {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-xxxs);
|
||||||
background-color: var(--blue-dark);
|
background-color: var(--blue-dark);
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
padding: var(--spacing-xxs) var(--spacing-xs);
|
padding: var(--spacing-xxs) var(--spacing-xs);
|
||||||
|
|
@ -39,10 +50,35 @@ export const Header = () => {
|
||||||
font-weight: var(--weight-medium);
|
font-weight: var(--weight-medium);
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.capsule.recording {
|
||||||
|
background: var(--secondary-default);
|
||||||
|
}
|
||||||
|
|
||||||
|
.capsule.recording span {
|
||||||
|
display: block;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
animation: capsulePulse 2s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes capsulePulse {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.25;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
</header>
|
</header>
|
||||||
),
|
),
|
||||||
[participantCount]
|
[participantCount, customCapsule]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ export default function Index({
|
||||||
domain,
|
domain,
|
||||||
isConfigured = false,
|
isConfigured = false,
|
||||||
predefinedRoom = false,
|
predefinedRoom = false,
|
||||||
|
forceFetchToken = false,
|
||||||
|
forceOwner = false,
|
||||||
asides,
|
asides,
|
||||||
modals,
|
modals,
|
||||||
customTrayComponent,
|
customTrayComponent,
|
||||||
|
|
@ -74,6 +76,8 @@ export default function Index({
|
||||||
<NotConfigured />
|
<NotConfigured />
|
||||||
) : (
|
) : (
|
||||||
<Intro
|
<Intro
|
||||||
|
forceFetchToken
|
||||||
|
forceOwner
|
||||||
title={process.env.PROJECT_TITLE}
|
title={process.env.PROJECT_TITLE}
|
||||||
room={roomName}
|
room={roomName}
|
||||||
error={tokenError}
|
error={tokenError}
|
||||||
|
|
@ -128,6 +132,8 @@ Index.propTypes = {
|
||||||
modals: PropTypes.arrayOf(PropTypes.func),
|
modals: PropTypes.arrayOf(PropTypes.func),
|
||||||
customTrayComponent: PropTypes.node,
|
customTrayComponent: PropTypes.node,
|
||||||
customAppComponent: PropTypes.node,
|
customAppComponent: PropTypes.node,
|
||||||
|
forceFetchToken: PropTypes.bool,
|
||||||
|
forceOwner: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getStaticProps() {
|
export async function getStaticProps() {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import App from '@dailyjs/basic-call/components/App';
|
import App from '@dailyjs/basic-call/components/App';
|
||||||
import { ChatProvider } from '../../contexts/ChatProvider';
|
import { LiveStreamingProvider } from '../../contexts/LiveStreamingProvider';
|
||||||
|
|
||||||
// Extend our basic call app component with the chat context
|
// Extend our basic call app component with the live streaming context
|
||||||
export const AppWithChat = () => (
|
export const AppWithLiveStreaming = () => (
|
||||||
<ChatProvider>
|
<LiveStreamingProvider>
|
||||||
<App />
|
<App />
|
||||||
</ChatProvider>
|
</LiveStreamingProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
export default AppWithChat;
|
export default AppWithLiveStreaming;
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
export { AppWithChat as default } from './App';
|
export { AppWithLiveStreaming as default } from './App';
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,49 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Button } from '@dailyjs/shared/components/Button';
|
import { Button } from '@dailyjs/shared/components/Button';
|
||||||
import Field from '@dailyjs/shared/components/Field';
|
import Field from '@dailyjs/shared/components/Field';
|
||||||
import { TextInput } from '@dailyjs/shared/components/Input';
|
import { TextInput } from '@dailyjs/shared/components/Input';
|
||||||
import Modal from '@dailyjs/shared/components/Modal';
|
import Modal from '@dailyjs/shared/components/Modal';
|
||||||
|
import { Well } from '@dailyjs/shared/components/Well';
|
||||||
import { useCallState } from '@dailyjs/shared/contexts/CallProvider';
|
import { useCallState } from '@dailyjs/shared/contexts/CallProvider';
|
||||||
import { useUIState } from '@dailyjs/shared/contexts/UIStateProvider';
|
import { useUIState } from '@dailyjs/shared/contexts/UIStateProvider';
|
||||||
|
import { useLiveStreaming } from '../../contexts/LiveStreamingProvider';
|
||||||
|
|
||||||
export const LIVE_STREAMING_MODAL = 'live-streaming';
|
export const LIVE_STREAMING_MODAL = 'live-streaming';
|
||||||
|
|
||||||
export const LiveStreamingModal = () => {
|
export const LiveStreamingModal = () => {
|
||||||
const { callObject } = useCallState();
|
const { callObject } = useCallState();
|
||||||
const { currentModals, closeModal } = useUIState();
|
const { currentModals, closeModal } = useUIState();
|
||||||
|
const { isStreaming, streamError } = useLiveStreaming();
|
||||||
|
const [pending, setPending] = useState(false);
|
||||||
const [rtmpUrl, setRtmpUrl] = useState('');
|
const [rtmpUrl, setRtmpUrl] = useState('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Reset pending state whenever stream state changes
|
||||||
|
setPending(false);
|
||||||
|
}, [isStreaming]);
|
||||||
|
|
||||||
|
function startLiveStream() {
|
||||||
|
setPending(true);
|
||||||
|
callObject.startLiveStreaming({ rtmpUrl });
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopLiveStreaming() {
|
||||||
|
setPending(true);
|
||||||
|
callObject.stopLiveStreaming();
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title="Live stream"
|
title="Live stream"
|
||||||
isOpen={currentModals[LIVE_STREAMING_MODAL]}
|
isOpen={currentModals[LIVE_STREAMING_MODAL]}
|
||||||
onClose={() => closeModal(LIVE_STREAMING_MODAL)}
|
onClose={() => closeModal(LIVE_STREAMING_MODAL)}
|
||||||
>
|
>
|
||||||
<Field label="Enter room to join">
|
{streamError && (
|
||||||
|
<Well variant="error">
|
||||||
|
Unable to start stream. Error message: {streamError}
|
||||||
|
</Well>
|
||||||
|
)}
|
||||||
|
<Field label="Enter RTMP endpoint">
|
||||||
<TextInput
|
<TextInput
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="RTMP URL"
|
placeholder="RTMP URL"
|
||||||
|
|
@ -27,15 +51,18 @@ export const LiveStreamingModal = () => {
|
||||||
onChange={(e) => setRtmpUrl(e.target.value)}
|
onChange={(e) => setRtmpUrl(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
<Button
|
{!isStreaming ? (
|
||||||
disabled={!rtmpUrl}
|
<Button
|
||||||
onClick={() => callObject.startLiveStreaming({ rtmpUrl })}
|
disabled={!rtmpUrl || pending}
|
||||||
>
|
onClick={() => startLiveStream()}
|
||||||
Start live streaming
|
>
|
||||||
</Button>
|
{pending ? 'Starting stream...' : 'Start live streaming'}
|
||||||
<Button onClick={() => callObject.stopLiveStreaming()}>
|
</Button>
|
||||||
Stop live streaming
|
) : (
|
||||||
</Button>
|
<Button variant="warning" onClick={() => stopLiveStreaming()}>
|
||||||
|
Stop live streaming
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,18 @@ import { TrayButton } from '@dailyjs/shared/components/Tray';
|
||||||
import { useUIState } from '@dailyjs/shared/contexts/UIStateProvider';
|
import { useUIState } from '@dailyjs/shared/contexts/UIStateProvider';
|
||||||
import { ReactComponent as IconStream } from '@dailyjs/shared/icons/streaming-md.svg';
|
import { ReactComponent as IconStream } from '@dailyjs/shared/icons/streaming-md.svg';
|
||||||
|
|
||||||
|
import { useLiveStreaming } from '../../contexts/LiveStreamingProvider';
|
||||||
import { LIVE_STREAMING_MODAL } from '../LiveStreamingModal';
|
import { LIVE_STREAMING_MODAL } from '../LiveStreamingModal';
|
||||||
|
|
||||||
export const Tray = () => {
|
export const Tray = () => {
|
||||||
const { openModal } = useUIState();
|
const { openModal } = useUIState();
|
||||||
|
const { isStreaming } = useLiveStreaming();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TrayButton
|
<TrayButton
|
||||||
label="Stream"
|
label={isStreaming ? 'Live' : 'Stream'}
|
||||||
|
orange={isStreaming}
|
||||||
onClick={() => openModal(LIVE_STREAMING_MODAL)}
|
onClick={() => openModal(LIVE_STREAMING_MODAL)}
|
||||||
>
|
>
|
||||||
<IconStream />
|
<IconStream />
|
||||||
|
|
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
import React, {
|
|
||||||
createContext,
|
|
||||||
useCallback,
|
|
||||||
useContext,
|
|
||||||
useEffect,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
import { useCallState } from '@dailyjs/shared/contexts/CallProvider';
|
|
||||||
import { nanoid } from 'nanoid';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
export const ChatContext = createContext();
|
|
||||||
|
|
||||||
export const ChatProvider = ({ children }) => {
|
|
||||||
const { callObject } = useCallState();
|
|
||||||
const [chatHistory, setChatHistory] = useState([]);
|
|
||||||
const [hasNewMessages, setHasNewMessages] = useState(false);
|
|
||||||
|
|
||||||
const handleNewMessage = useCallback(
|
|
||||||
(e) => {
|
|
||||||
const participants = callObject.participants();
|
|
||||||
const sender = participants[e.fromId].user_name
|
|
||||||
? participants[e.fromId].user_name
|
|
||||||
: 'Guest';
|
|
||||||
|
|
||||||
setChatHistory((oldState) => [
|
|
||||||
...oldState,
|
|
||||||
{ sender, message: e.data.message, id: nanoid() },
|
|
||||||
]);
|
|
||||||
|
|
||||||
setHasNewMessages(true);
|
|
||||||
},
|
|
||||||
[callObject]
|
|
||||||
);
|
|
||||||
|
|
||||||
const sendMessage = useCallback(
|
|
||||||
(message) => {
|
|
||||||
if (!callObject) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('💬 Sending app message');
|
|
||||||
|
|
||||||
callObject.sendAppMessage({ message }, '*');
|
|
||||||
|
|
||||||
// Get the sender (local participant) name
|
|
||||||
const sender = callObject.participants().local.user_name
|
|
||||||
? callObject.participants().local.user_name
|
|
||||||
: 'Guest';
|
|
||||||
|
|
||||||
// Update local chat history
|
|
||||||
return setChatHistory((oldState) => [
|
|
||||||
...oldState,
|
|
||||||
{ sender, message, id: nanoid(), isLocal: true },
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
[callObject]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!callObject) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`💬 Chat provider listening for app messages`);
|
|
||||||
|
|
||||||
callObject.on('app-message', handleNewMessage);
|
|
||||||
|
|
||||||
return () => callObject.off('app-message', handleNewMessage);
|
|
||||||
}, [callObject, handleNewMessage]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ChatContext.Provider
|
|
||||||
value={{
|
|
||||||
sendMessage,
|
|
||||||
chatHistory,
|
|
||||||
hasNewMessages,
|
|
||||||
setHasNewMessages,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</ChatContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
ChatProvider.propTypes = {
|
|
||||||
children: PropTypes.node,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useChat = () => useContext(ChatContext);
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
import React, {
|
||||||
|
useState,
|
||||||
|
createContext,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useCallback,
|
||||||
|
} from 'react';
|
||||||
|
import { useCallState } from '@dailyjs/shared/contexts/CallProvider';
|
||||||
|
import { useUIState } from '@dailyjs/shared/contexts/UIStateProvider';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
export const LiveStreamingContext = createContext();
|
||||||
|
|
||||||
|
export const LiveStreamingProvider = ({ children }) => {
|
||||||
|
const [isStreaming, setIsStreaming] = useState(false);
|
||||||
|
const [streamError, setStreamError] = useState();
|
||||||
|
const { setCustomCapsule } = useUIState();
|
||||||
|
const { callObject } = useCallState();
|
||||||
|
|
||||||
|
const handleStreamStarted = useCallback(() => {
|
||||||
|
console.log('📺 Live stream started');
|
||||||
|
setIsStreaming(true);
|
||||||
|
setCustomCapsule({ variant: 'recording', label: 'Live streaming' });
|
||||||
|
}, [setCustomCapsule]);
|
||||||
|
|
||||||
|
const handleStreamStopped = useCallback(() => {
|
||||||
|
console.log('📺 Live stream stopped');
|
||||||
|
setIsStreaming(false);
|
||||||
|
setCustomCapsule(null);
|
||||||
|
}, [setCustomCapsule]);
|
||||||
|
|
||||||
|
const handleStreamError = useCallback(
|
||||||
|
(e) => {
|
||||||
|
setIsStreaming(false);
|
||||||
|
setCustomCapsule(null);
|
||||||
|
setStreamError(e.errorMsg);
|
||||||
|
},
|
||||||
|
[setCustomCapsule]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!callObject) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('📺 Live streaming provider listening for stream events');
|
||||||
|
|
||||||
|
callObject.on('live-streaming-started', handleStreamStarted);
|
||||||
|
callObject.on('live-streaming-stopped', handleStreamStopped);
|
||||||
|
callObject.on('live-streaming-error', handleStreamError);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
callObject.off('live-streaming-started', handleStreamStarted);
|
||||||
|
callObject.off('live-streaming-stopped', handleStreamStopped);
|
||||||
|
callObject.on('live-streaming-error', handleStreamError);
|
||||||
|
};
|
||||||
|
}, [callObject, handleStreamStarted, handleStreamStopped, handleStreamError]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LiveStreamingContext.Provider value={{ isStreaming, streamError }}>
|
||||||
|
{children}
|
||||||
|
</LiveStreamingContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
LiveStreamingProvider.propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useLiveStreaming = () => useContext(LiveStreamingContext);
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
import { useEffect, useMemo } from 'react';
|
|
||||||
|
|
||||||
import { useSound } from '@dailyjs/shared/hooks/useSound';
|
|
||||||
import { debounce } from 'debounce';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience hook to play `join.mp3` when participants join the call
|
|
||||||
*/
|
|
||||||
export const useMessageSound = () => {
|
|
||||||
const { load, play } = useSound('message.mp3');
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
load();
|
|
||||||
}, [load]);
|
|
||||||
|
|
||||||
return useMemo(() => debounce(() => play(), 5000, true), [play]);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useMessageSound;
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import App from '@dailyjs/basic-call/pages/_app';
|
import App from '@dailyjs/basic-call/pages/_app';
|
||||||
import AppWithChat from '../components/App';
|
import AppWithLiveStreaming from '../components/App';
|
||||||
|
|
||||||
import { LiveStreamingModal } from '../components/LiveStreamingModal';
|
import { LiveStreamingModal } from '../components/LiveStreamingModal';
|
||||||
import Tray from '../components/Tray';
|
import Tray from '../components/Tray';
|
||||||
|
|
||||||
App.modals = [LiveStreamingModal];
|
App.modals = [LiveStreamingModal];
|
||||||
App.customAppComponent = <AppWithChat />;
|
App.customAppComponent = <AppWithLiveStreaming />;
|
||||||
App.customTrayComponent = <Tray />;
|
App.customTrayComponent = <Tray />;
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ export async function getStaticProps() {
|
||||||
props: {
|
props: {
|
||||||
domain: process.env.DAILY_DOMAIN || null,
|
domain: process.env.DAILY_DOMAIN || null,
|
||||||
isConfigured,
|
isConfigured,
|
||||||
|
forceFetchToken: true,
|
||||||
|
forceOwner: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ export const GlobalStyle = () => (
|
||||||
--primary-dark: ${theme.primary.dark};
|
--primary-dark: ${theme.primary.dark};
|
||||||
--secondary-default: ${theme.secondary.default};
|
--secondary-default: ${theme.secondary.default};
|
||||||
--secondary-dark: ${theme.secondary.dark};
|
--secondary-dark: ${theme.secondary.dark};
|
||||||
|
--secondary-light: ${theme.secondary.light};
|
||||||
--blue-light: ${theme.blue.light};
|
--blue-light: ${theme.blue.light};
|
||||||
--blue-default: ${theme.blue.default};
|
--blue-default: ${theme.blue.default};
|
||||||
--blue-dark: ${theme.blue.dark};
|
--blue-dark: ${theme.blue.dark};
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ export const UIStateProvider = ({
|
||||||
}) => {
|
}) => {
|
||||||
const [showAside, setShowAside] = useState();
|
const [showAside, setShowAside] = useState();
|
||||||
const [activeModals, setActiveModals] = useState({});
|
const [activeModals, setActiveModals] = useState({});
|
||||||
|
const [customCapsule, setCustomCapsule] = useState();
|
||||||
|
|
||||||
const openModal = useCallback((modalName) => {
|
const openModal = useCallback((modalName) => {
|
||||||
setActiveModals((prevState) => ({
|
setActiveModals((prevState) => ({
|
||||||
|
|
@ -45,6 +46,8 @@ export const UIStateProvider = ({
|
||||||
toggleAside,
|
toggleAside,
|
||||||
showAside,
|
showAside,
|
||||||
setShowAside,
|
setShowAside,
|
||||||
|
customCapsule,
|
||||||
|
setCustomCapsule,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ export const defaultTheme = {
|
||||||
secondary: {
|
secondary: {
|
||||||
default: '#FF9254',
|
default: '#FF9254',
|
||||||
dark: '#FB651E',
|
dark: '#FB651E',
|
||||||
|
light: '#FF9254',
|
||||||
},
|
},
|
||||||
|
|
||||||
blue: {
|
blue: {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue