Skip to content

Commit

Permalink
feat: improve editor and routing transition loading with suspense (#350)
Browse files Browse the repository at this point in the history
* feat: improve editor page load with suspense
* feat: suspense and state sync improvements
  • Loading branch information
riccardoperra authored Aug 31, 2022
1 parent 0b9c911 commit dd93b28
Show file tree
Hide file tree
Showing 21 changed files with 505 additions and 345 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import {useI18n} from '@codeimage/locale';
import {getRootEditorStore} from '@codeimage/store/editor';
import {dispatchUpdateTheme} from '@codeimage/store/effects/onThemeChange';
import {getFrameState} from '@codeimage/store/editor/frame';
import {getTerminalState} from '@codeimage/store/editor/terminal';
import {dispatchUpdateTheme} from '@codeimage/store/effects/onThemeChange';
import * as ui from '@codeimage/store/ui';
import {
Button,
FadeInOutTransition,
HStack,
PopoverPanel,
PortalHostContext,
useFloating,
Expand Down
122 changes: 70 additions & 52 deletions apps/codeimage/src/components/PropertyEditor/EditorStyleForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import {getActiveEditorStore} from '@codeimage/store/editor/activeEditor';
import {SegmentedField, Select, Text} from '@codeimage/ui';
import {SUPPORTED_FONTS} from '@core/configuration/font';
import {useModality} from '@core/hooks/isMobile';
import {SkeletonLine} from '@ui/Skeleton/Skeleton';
import {createMemo, ParentComponent, Show} from 'solid-js';
import {AppLocaleEntries} from '../../i18n';
import {PanelHeader} from './PanelHeader';
import {PanelRow, TwoColumnPanelRow} from './PanelRow';
import {SuspenseEditorItem} from './SuspenseEditorItemt';

export const EditorStyleForm: ParentComponent = () => {
const languages = SUPPORTED_LANGUAGES;
Expand Down Expand Up @@ -44,21 +46,25 @@ export const EditorStyleForm: ParentComponent = () => {

<PanelRow for={'frameLanguageField'} label={t('frame.language')}>
<TwoColumnPanelRow>
<Select
id={'frameLanguageField'}
multiple={false}
native={modality === 'mobile'}
items={languages.map(({label, id}) => ({
label: label,
value: id,
}))}
value={editor.languageId}
onSelectChange={value => {
const language = value ?? languages[0].id;
setLanguageId(language);
umami.trackEvent(language, 'change-language');
}}
/>
<SuspenseEditorItem
fallback={<SkeletonLine width={'100%'} height={'26px'} />}
>
<Select
id={'frameLanguageField'}
multiple={false}
native={modality === 'mobile'}
items={languages.map(({label, id}) => ({
label: label,
value: id,
}))}
value={editor.languageId}
onSelectChange={value => {
const language = value ?? languages[0].id;
setLanguageId(language);
umami.trackEvent(language, 'change-language');
}}
/>
</SuspenseEditorItem>
</TwoColumnPanelRow>
</PanelRow>

Expand All @@ -67,53 +73,65 @@ export const EditorStyleForm: ParentComponent = () => {
label={t('frame.lineNumbers')}
>
<TwoColumnPanelRow>
<SegmentedField
size={'xs'}
id={'frameLineNumbersField'}
value={state.options.showLineNumbers}
onChange={setShowLineNumbers}
items={[
{label: t('common.show'), value: true},
{label: t('common.hide'), value: false},
]}
/>
<SuspenseEditorItem
fallback={<SkeletonLine width={'100%'} height={'26px'} />}
>
<SegmentedField
size={'xs'}
id={'frameLineNumbersField'}
value={state.options.showLineNumbers}
onChange={setShowLineNumbers}
items={[
{label: t('common.show'), value: true},
{label: t('common.hide'), value: false},
]}
/>
</SuspenseEditorItem>
</TwoColumnPanelRow>
</PanelRow>

<PanelRow for={'frameFontField'} label={t('frame.font')}>
<TwoColumnPanelRow>
<Select
id={'frameFontField'}
native={modality === 'mobile'}
multiple={false}
items={fontOptions()}
value={font()}
itemContent={({label, value, selected}) => (
<Text
size={'xs'}
weight={selected ? 'medium' : 'normal'}
style={{'font-family': `${value.name}, monospace`}}
>
{label}
</Text>
)}
onSelectChange={value => setFontId(value?.id ?? fonts[0].id)}
/>
<SuspenseEditorItem
fallback={<SkeletonLine width={'100%'} height={'26px'} />}
>
<Select
id={'frameFontField'}
native={modality === 'mobile'}
multiple={false}
items={fontOptions()}
value={font()}
itemContent={({label, value, selected}) => (
<Text
size={'xs'}
weight={selected ? 'medium' : 'normal'}
style={{'font-family': `${value.name}, monospace`}}
>
{label}
</Text>
)}
onSelectChange={value => setFontId(value?.id ?? fonts[0].id)}
/>
</SuspenseEditorItem>
</TwoColumnPanelRow>
</PanelRow>

<PanelRow for={'frameFontWeightField'} label={t('frame.fontWeight')}>
<TwoColumnPanelRow>
<Select
id={'frameFontWeightField'}
native={modality === 'mobile'}
multiple={false}
items={fontWeightOptions()}
value={state.options.fontWeight}
onSelectChange={value =>
setFontWeight(value ?? font()?.types[0].weight ?? 400)
}
/>
<SuspenseEditorItem
fallback={<SkeletonLine width={'85%'} height={'26px'} />}
>
<Select
id={'frameFontWeightField'}
native={modality === 'mobile'}
multiple={false}
items={fontWeightOptions()}
value={state.options.fontWeight}
onSelectChange={value =>
setFontWeight(value ?? font()?.types[0].weight ?? 400)
}
/>
</SuspenseEditorItem>
</TwoColumnPanelRow>
</PanelRow>
</>
Expand Down
88 changes: 55 additions & 33 deletions apps/codeimage/src/components/PropertyEditor/FrameStyleForm.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {useI18n} from '@codeimage/locale';
import {getFrameState} from '@codeimage/store/editor/frame';
import {RangeField, SegmentedField} from '@codeimage/ui';
import {SkeletonLine, SkeletonVCenter} from '@ui/Skeleton/Skeleton';
import {ParentComponent, Show} from 'solid-js';
import {appEnvironment} from '../../core/configuration';
import {AppLocaleEntries} from '../../i18n';
import {CustomColorPicker} from './controls/CustomColorPicker';
import {PanelHeader} from './PanelHeader';
import {PanelRow, TwoColumnPanelRow} from './PanelRow';
import {SuspenseEditorItem} from './SuspenseEditorItemt';

export const FrameStyleForm: ParentComponent = () => {
const [t] = useI18n<AppLocaleEntries>();
Expand All @@ -19,57 +21,77 @@ export const FrameStyleForm: ParentComponent = () => {

<PanelRow for={'paddingField'} label={t('frame.padding')}>
<TwoColumnPanelRow>
<SegmentedField
id={'paddingField'}
size={'xs'}
value={frame.store.padding}
onChange={frame.setPadding}
items={editorPadding.map(padding => ({
label: padding.toString(),
value: padding,
}))}
/>
<SuspenseEditorItem
fallback={<SkeletonLine width={'100%'} height={'26px'} />}
>
<SegmentedField
id={'paddingField'}
size={'xs'}
value={frame.store.padding}
onChange={frame.setPadding}
items={editorPadding.map(padding => ({
label: padding.toString(),
value: padding,
}))}
/>
</SuspenseEditorItem>
</TwoColumnPanelRow>
</PanelRow>

<PanelRow for={'visibleField'} label={t('frame.visible')}>
<TwoColumnPanelRow>
<SegmentedField
id={'visibleField'}
size={'xs'}
value={frame.store.visible}
onChange={frame.setVisibility}
items={[
{label: t('common.yes'), value: true},
{label: t('common.no'), value: false},
]}
/>
<SuspenseEditorItem
fallback={<SkeletonLine width={'100%'} height={'26px'} />}
>
<SegmentedField
id={'visibleField'}
size={'xs'}
value={frame.store.visible}
onChange={frame.setVisibility}
items={[
{label: t('common.yes'), value: true},
{label: t('common.no'), value: false},
]}
/>
</SuspenseEditorItem>
</TwoColumnPanelRow>
</PanelRow>

<Show when={frame.store.visible}>
<PanelRow for={'opacityField'} label={t('frame.opacity')}>
<TwoColumnPanelRow>
<RangeField
id={'opacityField'}
value={frame.store.opacity}
min={0}
disabled={!frame.store.visible}
max={100}
onChange={frame.setOpacity}
/>
<SuspenseEditorItem
fallback={
<SkeletonVCenter>
<SkeletonLine width={'100%'} height={'24px'} />
</SkeletonVCenter>
}
>
<RangeField
id={'opacityField'}
value={frame.store.opacity}
min={0}
disabled={!frame.store.visible}
max={100}
onChange={frame.setOpacity}
/>
</SuspenseEditorItem>
</TwoColumnPanelRow>
</PanelRow>
</Show>

<Show when={frame.store.visible}>
<PanelRow for={'colorField'} label={t('frame.color')}>
<TwoColumnPanelRow>
<CustomColorPicker
title={'Color'}
onChange={color => frame.setBackground(color)}
value={frame.store.background ?? ''}
/>
<SuspenseEditorItem
fallback={<SkeletonLine width={'100%'} height={'26px'} />}
>
<CustomColorPicker
title={'Color'}
onChange={color => frame.setBackground(color)}
value={frame.store.background ?? ''}
/>
</SuspenseEditorItem>
</TwoColumnPanelRow>
</PanelRow>
</Show>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {getEditorSyncAdapter} from '@codeimage/store/editor/createEditorInit';
import {JSX, ParentProps, Suspense} from 'solid-js';

export function SuspenseEditorItem(
props: ParentProps<{fallback: JSX.Element}>,
) {
const {loadedSnippet} = getEditorSyncAdapter()!;

const render = () => {
loadedSnippet();
return true;
};

return (
<Suspense fallback={props.fallback}>{render() && props.children}</Suspense>
);
}
Loading

0 comments on commit dd93b28

Please sign in to comment.