Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Single URLs layout #1326

Merged
merged 11 commits into from
Feb 5, 2024
2 changes: 1 addition & 1 deletion app/charts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ export const getInitialSymbolLayer = ({
};
};

const META: Meta = {
export const META: Meta = {
title: {
en: "",
de: "",
Expand Down
69 changes: 64 additions & 5 deletions app/components/chart-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
import { ChartWithFilters } from "@/components/chart-with-filters";
import DebugPanel from "@/components/debug-panel";
import Flex from "@/components/flex";
import { Checkbox } from "@/components/form";
import { HintYellow } from "@/components/hint";
import { MetadataPanel } from "@/components/metadata-panel";
import {
Expand Down Expand Up @@ -70,6 +71,8 @@ export const ChartPreview = (props: ChartPreviewProps) => {

return layout.type === "dashboard" && !editing ? (
<DashboardPreview dataSource={dataSource} layoutType={layout.layout} />
) : layout.type === "singleURLs" ? (
<SingleURLsPreview dataSource={dataSource} layout={layout} />
) : (
<ChartTablePreviewProvider>
<ChartWrapper editing={editing} layoutType={layout.type}>
Expand Down Expand Up @@ -169,7 +172,7 @@ const DashboardPreview = (props: DashboardPreviewProps) => {
<ChartPreviewInner
dataSource={dataSource}
chartKey={activeChartKey}
dragHandleSlot={<DragHandle dragging />}
actionElementSlot={<DragHandle dragging />}
/>
</ChartWrapper>
</DragOverlay>
Expand Down Expand Up @@ -233,7 +236,7 @@ const DndChartPreview = (props: DndChartPreviewProps) => {
<ChartPreviewInner
dataSource={dataSource}
chartKey={chartKey}
dragHandleSlot={
actionElementSlot={
<DragHandle
{...listeners}
ref={setActivatorNodeRef}
Expand All @@ -246,14 +249,70 @@ const DndChartPreview = (props: DndChartPreviewProps) => {
);
};

type SingleURLsPreviewProps = ChartPreviewProps & {
layout: Extract<Layout, { type: "singleURLs" }>;
};

const SingleURLsPreview = (props: SingleURLsPreviewProps) => {
const { dataSource, layout } = props;
const [state, dispatch] = useConfiguratorState(hasChartConfigs);
const renderChart = React.useCallback(
(chartConfig: ChartConfig) => {
const checked = layout.publishableChartKeys.includes(chartConfig.key);
const { publishableChartKeys: keys } = layout;
const { key } = chartConfig;

return (
<ChartTablePreviewProvider>
<ChartWrapper>
<ChartPreviewInner
dataSource={dataSource}
chartKey={chartConfig.key}
actionElementSlot={
<Checkbox
checked={checked}
disabled={keys.length === 1 && checked}
onChange={() => {
dispatch({
type: "LAYOUT_CHANGED",
value: {
...layout,
publishableChartKeys: checked
? keys.filter((k) => k !== key)
: state.chartConfigs
.map((c) => c.key)
.filter((k) => keys.includes(k) || k === key),
},
});
}}
label=""
/>
}
/>
</ChartWrapper>
</ChartTablePreviewProvider>
);
},
[dataSource, dispatch, layout, state.chartConfigs]
);

return (
<ChartPanelLayoutVertical
chartConfigs={state.chartConfigs}
renderChart={renderChart}
/>
);
};

type ChartPreviewInnerProps = ChartPreviewProps & {
chartKey?: string | null;
dragHandleSlot?: React.ReactNode;
actionElementSlot?: React.ReactNode;
disableMetadataPanel?: boolean;
};

export const ChartPreviewInner = (props: ChartPreviewInnerProps) => {
const { dataSource, chartKey, dragHandleSlot, disableMetadataPanel } = props;
const { dataSource, chartKey, actionElementSlot, disableMetadataPanel } =
props;
const [state, dispatch] = useConfiguratorState();
const chartConfig = getChartConfig(state, chartKey);
const locale = useLocale();
Expand Down Expand Up @@ -393,7 +452,7 @@ export const ChartPreviewInner = (props: ChartPreviewInnerProps) => {
top={96}
/>
)}
{dragHandleSlot}
{actionElementSlot}
</Flex>
</Flex>
{(state.state === "CONFIGURING_CHART" ||
Expand Down
2 changes: 1 addition & 1 deletion app/components/debug-panel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { DebugPanelProps } from "./DebugPanel";
const LazyDebugPanel = dynamic(() => import("./DebugPanel"), { ssr: false });

const DebugPanel = (props: DebugPanelProps) => {
const shouldShow = flag("debug") || process.env.NODE_ENV === "development";
const shouldShow = flag("debug") ?? process.env.NODE_ENV === "development";

if (!shouldShow) {
return null;
Expand Down
2 changes: 1 addition & 1 deletion app/components/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ export const Checkbox = ({
className,
}: CheckboxProps) => (
<FormControlLabel
label={label || "-"}
label={label}
htmlFor={`${name}`}
disabled={disabled}
className={className}
Expand Down
5 changes: 5 additions & 0 deletions app/config-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,11 @@ const Layout = t.intersection([
layout: t.union([t.literal("vertical"), t.literal("tall")]),
meta: Meta,
}),
t.type({
type: t.literal("singleURLs"),
publishableChartKeys: t.array(t.string),
meta: Meta,
}),
]),
]);
export type Layout = t.TypeOf<typeof Layout>;
Expand Down
125 changes: 91 additions & 34 deletions app/configurator/components/configurator.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Trans } from "@lingui/macro";
import { SxProps } from "@mui/material";
import { SxProps, Typography } from "@mui/material";
import Box from "@mui/material/Box";
import Button, { ButtonProps } from "@mui/material/Button";
import { useRouter } from "next/router";
import React from "react";

import { SelectDatasetStep } from "@/browser/select-dataset-step";
import { META } from "@/charts";
import { ChartPreview } from "@/components/chart-preview";
import { PublishChartButton } from "@/components/chart-selection-tabs";
import { HEADER_HEIGHT } from "@/components/header";
Expand Down Expand Up @@ -224,8 +225,14 @@ const LayoutingStep = () => {
return null;
}

const isSingleURLs = state.layout.type === "singleURLs";

return (
<PanelLayout type="LM" sx={{ background: (t) => t.palette.muted.main }}>
<PanelLayout
// SingleURLs layout doesn't have an options panel
type={isSingleURLs ? "M" : "LM"}
sx={{ background: (t) => t.palette.muted.main }}
>
<PanelHeaderLayout type="LMR">
<PanelHeaderWrapper type="L">
<BackContainer>
Expand Down Expand Up @@ -283,6 +290,29 @@ const LayoutingStep = () => {
});
}}
/>
<IconButton
label="layoutSingleURLs"
checked={state.layout.type === "singleURLs"}
onClick={() => {
if (state.layout.type === "singleURLs") {
return;
}

dispatch({
type: "LAYOUT_CHANGED",
value: {
type: "singleURLs",
publishableChartKeys: state.chartConfigs.map(
(chartConfig) => chartConfig.key
),
// Clear the meta data, as it's not used in singleURLs layout,
// but makes the types more consistent
meta: META,
activeField: undefined,
},
});
}}
/>
</PanelHeaderWrapper>
<PanelHeaderWrapper
type="R"
Expand All @@ -295,43 +325,70 @@ const LayoutingStep = () => {
<PublishChartButton />
</PanelHeaderWrapper>
</PanelHeaderLayout>
<PanelBodyWrapper type="L">
<LayoutConfigurator />
</PanelBodyWrapper>
{!isSingleURLs && (
<PanelBodyWrapper type="L">
<LayoutConfigurator />
</PanelBodyWrapper>
)}
<PanelBodyWrapper type="M">
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: 1,
mt: 3,
mb: 4,
}}
sx={
isSingleURLs
? {
width: "100%",
maxWidth: { xs: "100%", lg: 1280 },
mx: "auto",
}
: {}
}
>
<Title
text={state.layout.meta.title[locale]}
onClick={() => {
if (state.layout.activeField !== "title") {
dispatch({
type: "LAYOUT_ACTIVE_FIELD_CHANGED",
value: "title",
});
}
}}
/>
<Description
text={state.layout.meta.description[locale]}
onClick={() => {
if (state.layout.activeField !== "description") {
dispatch({
type: "LAYOUT_ACTIVE_FIELD_CHANGED",
value: "description",
});
}
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: 1,
mt: 3,
mb: isSingleURLs ? 6 : 4,
}}
/>
>
{isSingleURLs ? (
<Typography
variant="h3"
sx={{ fontWeight: "normal", color: "secondary.active" }}
>
<Trans id="controls.layout.singleURLs.publish">
Select the charts to publish separately.
</Trans>
</Typography>
) : (
<>
<Title
text={state.layout.meta.title[locale]}
onClick={() => {
if (state.layout.activeField !== "title") {
dispatch({
type: "LAYOUT_ACTIVE_FIELD_CHANGED",
value: "title",
});
}
}}
/>
<Description
text={state.layout.meta.description[locale]}
onClick={() => {
if (state.layout.activeField !== "description") {
dispatch({
type: "LAYOUT_ACTIVE_FIELD_CHANGED",
value: "description",
});
}
}}
/>
</>
)}
</Box>
<ChartPreview dataSource={state.dataSource} />
</Box>
<ChartPreview dataSource={state.dataSource} />
</PanelBodyWrapper>
<ConfiguratorDrawer
anchor="left"
Expand Down
6 changes: 6 additions & 0 deletions app/configurator/components/field-i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ const fieldLabels = {
id: "controls.layout.dashboard",
message: "Dashboard",
}),
"controls.layout.singleURLs": defineMessage({
id: "controls.layout.singleURLs",
message: "Single URLs",
}),
"controls.layout.tall": defineMessage({
id: "controls.layout.tall",
message: "Tall",
Expand Down Expand Up @@ -379,6 +383,8 @@ export function getFieldLabel(field: string): string {
return i18n._(fieldLabels["controls.layout.tall"]);
case "layoutVertical":
return i18n._(fieldLabels["controls.layout.vertical"]);
case "layoutSingleURLs":
return i18n._(fieldLabels["controls.layout.singleURLs"]);

// Languages
case "en":
Expand Down
2 changes: 2 additions & 0 deletions app/configurator/components/ui-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ export const getIconName = (name: string): IconName => {
return "time";
case "animation":
return "animation";
case "layoutSingleURLs":
return "layoutSingleURLs";
case "layoutTab":
return "layoutTab";
case "layoutDashboard":
Expand Down
Loading
Loading