fix(ui): prevent layerchart circular dependency in thumbs submissions
This commit is contained in:
@@ -431,6 +431,37 @@ When cleanup or reset must follow a specific lifecycle moment, use the matching
|
|||||||
|
|
||||||
Use `.server.ts` files for server-side code to isolate API keys.
|
Use `.server.ts` files for server-side code to isolate API keys.
|
||||||
|
|
||||||
|
### Chart Imports and SSR
|
||||||
|
|
||||||
|
`layerchart` has internal circular dependencies that Vite cannot reliably evaluate during SSR. Never statically import `layerchart` or the `@cio/ui/base/chart` runtime barrel from a component that can enter the server module graph.
|
||||||
|
|
||||||
|
- Import chart types from the dependency-free types module: `import type { ChartConfig } from '@cio/ui/base/chart/types'` (or the equivalent relative path inside `packages/ui`).
|
||||||
|
- Load chart runtime components with a browser-only dynamic import and render them inside an `{#await}` block guarded by `browser` or `typeof window !== 'undefined'`.
|
||||||
|
- In exercise submission renderers, reuse `submission-response-bar-chart.svelte` or `submission-response-pie-chart.svelte`; do not import the chart barrel directly.
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<script module lang="ts">
|
||||||
|
function loadChart() {
|
||||||
|
if (typeof window === 'undefined') return Promise.reject(new Error('browser-only'));
|
||||||
|
|
||||||
|
return import('@cio/ui/base/chart');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { browser } from '$app/environment';
|
||||||
|
import type { ChartConfig } from '@cio/ui/base/chart/types';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if browser}
|
||||||
|
{#await loadChart() then Chart}
|
||||||
|
<Chart.ChartContainer {config}>
|
||||||
|
<Chart.BarChart data={chartData} x="label" y="value" />
|
||||||
|
</Chart.ChartContainer>
|
||||||
|
{/await}
|
||||||
|
{/if}
|
||||||
|
```
|
||||||
|
|
||||||
### UI Components
|
### UI Components
|
||||||
|
|
||||||
- Add new UI components under `packages/ui/src` following existing folder patterns.
|
- Add new UI components under `packages/ui/src` following existing folder patterns.
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as Chart from '../../../../base/chart';
|
|
||||||
import type { ExerciseQuestionRendererProps } from '@cio/question-types';
|
import type { ExerciseQuestionRendererProps } from '@cio/question-types';
|
||||||
|
import type { ChartConfig } from '../../../../base/chart/types';
|
||||||
|
|
||||||
|
import SubmissionResponsePieChart from '../shared/submission-response-pie-chart.svelte';
|
||||||
import { getAnswerForQuestion, getSubmissionLabel, normalizeLabel, withChartColors } from '../submission-utils';
|
import { getAnswerForQuestion, getSubmissionLabel, normalizeLabel, withChartColors } from '../submission-utils';
|
||||||
|
|
||||||
let {
|
let {
|
||||||
@@ -30,7 +31,7 @@
|
|||||||
label: getSubmissionLabel(labels, 'submission.chart.responses', 'Responses'),
|
label: getSubmissionLabel(labels, 'submission.chart.responses', 'Responses'),
|
||||||
color: 'var(--chart-1)'
|
color: 'var(--chart-1)'
|
||||||
}
|
}
|
||||||
} satisfies Chart.ChartConfig);
|
} satisfies ChartConfig);
|
||||||
|
|
||||||
const chartData = $derived.by(() => {
|
const chartData = $derived.by(() => {
|
||||||
let yesCount = 0;
|
let yesCount = 0;
|
||||||
@@ -81,13 +82,8 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if chartData.length > 0}
|
<SubmissionResponsePieChart
|
||||||
<Chart.Container config={chartConfig} class="ui:h-[280px] ui:w-full ui:flex-col ui:items-center">
|
{chartData}
|
||||||
<Chart.PieChart data={chartData} key="key" label="label" value="responses" c="color" />
|
{chartConfig}
|
||||||
<Chart.ChartLegend items={chartData.map((d) => ({ label: d.label, color: d.color, value: d.responses }))} />
|
emptyLabel={getSubmissionLabel(labels, 'submission.chart.no_data', 'No responses yet')}
|
||||||
</Chart.Container>
|
/>
|
||||||
{:else}
|
|
||||||
<p class="ui:text-muted-foreground ui:text-sm">
|
|
||||||
{getSubmissionLabel(labels, 'submission.chart.no_data', 'No responses yet')}
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user