This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Before making any file edits or starting implementation, FIRST provide a concise summary of findings/plan to the user and wait for confirmation. Do not spend excessive time reading files without delivering intermediate findings.
When performing code reviews, ALWAYS use the svelte-code-writer skill for any Svelte (.svelte) file validation. Do not skip this step even if the review seems straightforward.
Svelte 5 data visualization comparing prison isolation sanctions and protection measures across three Spanish prison administrations (AGE, Cataluña, País Vasco). Created from the Civio Svelte 5 template.
sanciones-administracion/
├── index.html # HTML entry point with mount div
├── package.json # Dependencies and npm scripts
├── package-lock.json
├── vite.config.js # Vite + Svelte configuration
├── svelte.config.js # Svelte preprocessor config
├── jsconfig.json # JS/IDE config
├── oxlint.json # Linting rules
├── knip.json # Dead code detection config
├── generate-breakpoints.js # Playwright script for iframe heights
├── breakpoints-report.md # Generated breakpoints report
├── README.md # Embedding code and documentation
│
├── src/
│ ├── main.js # App mount point
│ ├── App.svelte # Main component
│ ├── vite-env.d.ts # Vite type declarations
│ │
│ ├── states/ # Reactive state (Svelte 5 runes)
│ │ ├── data.svelte.js # Data class and inline datasets
│ │ ├── language.svelte.js # i18n texts and formatters
│ │ └── utils.svelte.js # URL params, mobile detection, isCivio
│ │
│ ├── lib/ # Reusable components
│ │ ├── ChartContainer.svelte # Stacked bar chart (SVG, d3 scales)
│ │ ├── VerticalChart.svelte # Desktop vertical stacked bar chart
│ │ ├── HorizontalChart.svelte # Mobile horizontal stacked bar chart
│ │ ├── SvgPatternDefs.svelte # Shared SVG hatch pattern definitions
│ │ ├── Tooltip.svelte # Modal tooltip for sanction details
│ │ ├── ScreenReaderDescription.svelte
│ │ └── footer/
│ │ ├── Footer.svelte
│ │ └── ShareContainer.svelte
│ │
│ ├── utils/ # Helper functions
│ │ ├── colors.js # Civio color system
│ │ ├── locale.js # Number formatters
│ │ └── clickOutside.svelte.js
│ │
│ ├── a11y/ # Accessibility helpers
│ │ ├── index.js # Type definitions and exports
│ │ └── mainChart.js # Chart description generator
│ │
│ └── assets/ # Static assets
│ ├── civio.svg # Civio logo
│ └── civio-dots.svg # Civio dots pattern
│
├── public/ # Static files (copied to dist/)
│ ├── civio.png # Civio logo for sharing
│ └── iframes/ # Generated iframe HTML files
│
└── dist/ # Production build output
├── index.html
├── civio.png
├── iframes/
└── assets/
├── index.js
└── index.css
# Development
npm run dev # Start Vite dev server (localhost:5173)
npm run build # Production build to dist/
npm run preview # Preview production build
# Linting & Formatting
npm run lint # Run Oxlint on src/
npm run lint:fix # Auto-fix Oxlint issues
npm run lint:deps # Check unused dependencies with Knip
npm run lint:all # Full lint + dependency check
npm run format # Format with Prettier
npm run format:check # Check formatting
# Iframe Generation (generates one file per type × language)
npm run iframe # All types (sancion + proteccion) in Spanish
npm run iframe --languages=es,en # All types in Spanish and English
npm run iframe --type=sancion # Only sancion type in Spanish
npm run iframe --type=proteccion --languages=es,en # Only proteccion in Spanish and English
npm run iframe --selector=chart-id # Specific chart selector
npm run iframe:public # Generate iframes for public/ directoryindex.html- Contains two<div class="sanciones-administracion">mount points, one per chart type (type="sancion"andtype="proteccion")src/main.js- Mounts App component on each target div. Supports?type=URL param to mount only one chart type (used by iframe generation)
Located in src/states/:
data.svelte.js-Dataclass withvalue($state),grouped($derived via d3groups: year → administration → categories),loading,error. Data is hardcoded inline as exported arrays (sancion,proteccion), not fetched from networklanguage.svelte.js-Langclass with i18n texts (Spanish only), number formatters per languageutils.svelte.js- URL params (?lang=,?a11y,?alt,?type=),isCiviohostname detection, mobile breakpoint viaMediaQuery
src/App.svelte- Main component. Props:lang,chartID,a11y,alt,type. Assigns inline data (not network fetch), injects CSS color variables, supports a11y debug mode (?a11y) and alt description mode (?alt)src/lib/ChartContainer.svelte- Stacked bar chart: d3 scales, SVG bars per year/administration, toggle between ratio (‰) and absolute values. Contains centralized color functions:getCategoryColor(adm, catIndex, orientation)— for SVG fills (returns fill string, uses per-admin hatch patterns for sancion type)getCategoryBackground(adm, catIndex)— for div backgrounds (returns CSS background string, usesrepeating-linear-gradientfor hatched categories)
src/lib/VerticalChart.svelte- Desktop vertical stacked bar chart (SVG)src/lib/HorizontalChart.svelte- Mobile horizontal stacked bar chart (SVG)src/lib/SvgPatternDefs.svelte- Shared SVG<pattern>definitions for per-admin hatch patterns (used by both chart orientations)src/lib/Tooltip.svelte- Modal overlay showing sanction breakdown per administration for a selected year; receivesgetCategoryBackgroundfor consistent color rendering. Supports prev/next year navigation viayearIndex/yearCountsrc/lib/footer/Footer.svelte- Source/methodology text, share button. Receivestypefor unique DOM IDs per chart instancesrc/lib/footer/ShareContainer.svelte- Embed code copy. Usestypein iframe URL ({chartID}-{type}-{lang}-responsive.md)src/lib/ScreenReaderDescription.svelte- Renders accessible descriptions (list/table format). Supportsvisibleprop for alt mode display
src/utils/colors.js- Civio brand colors, project-specific palettes (justiciaarea), CSS variable generation. Admin palettes via CSS relative colors (makePalette): AGE (#c76deb), PV (#109bf6), CAT (#08a6bf) with auto-generated light/mid/dark variantssrc/utils/locale.js- Number formatters (ES/EN decimals, integers)src/utils/clickOutside.svelte.js- Click outside directive
src/a11y/mainChart.js-getMainChartA11y()generates table-format descriptions with ratio (‰) + total per admin per yearsrc/a11y/index.js-A11yDescriptiontypedef and re-exports- Debug mode: Add
?a11yURL param ordata-a11yattribute to visualize sr-only elements - Alt mode: Add
?altURL param ordata-altattribute to display the chart description visually below the chart
// In App.svelte — data is hardcoded, not fetched
import { Data, proteccion, sancion } from './states/data.svelte';
const chartData = new Data();
onMount(() => {
chartData.value = type === 'sancion' ? sancion : proteccion;
vizLang.setLang(urlInfo.lang ?? lang);
});export class Data {
value = $state(undefined);
grouped = $derived(this.value && groups(this.value, d => d.year, d => d.adm).map(...));
loading = $state(true);
error = $state(null);
}
// Instantiated per chart in App.svelte: const chartData = new Data();Colors are injected as CSS variables on the chart container:
--civio-blue,--civio-yellow,--civio-green,--civio-lightYellow,--civio-lightGreen(main brand)--primary,--secondary,--light(project area:justicia)--bw0to--bw990(grayscale ramp)--age,--cat,--pv(admin base colors) with_cat_1/_cat_2/_cat_3/_gradientvariants generated via CSS relative colors
This project renders two independent chart instances on the same page:
type="sancion"— sanction data (2 stacked categories: aislamiento + fin de semana, hatched pattern for 2nd category)type="proteccion"— protection isolation data (single category per admin, gradient colors)
Each type has its own data source, iframe file, and unique DOM IDs. The ?type= URL param isolates one chart for iframe measurement.
Charts are embedded via the code in README.md. The generate-breakpoints.js script uses Playwright to capture responsive heights for iframe generation. It iterates over types × languages, producing files like sanciones-administracion-sancion-es-responsive.md.