Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions apps/marketing/public/txt-demos/angular/analytics.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ import "@simple-table/angular/styles.css";
[rows]="rows"
[columns]="headers"
[enableColumnEditor]="true"
[expandAll]="nestedRows"
[getRowId]="getRowId"
height="100%"
[initialSortColumn]="isPivoted ? undefined : 'sales'"
Expand Down Expand Up @@ -138,7 +137,6 @@ export class AnalyticsDemoComponent {

activeId = analyticsPresets[0].id;
pivot: PivotConfig | null = analyticsPresets[0].pivot;
nestedRows = (analyticsPresets[0].pivot?.rows.length ?? 0) > 1;
isPivoted = analyticsPresets[0].pivot != null;
activeDescription = analyticsPresets[0].description;
searchText = "";
Expand Down Expand Up @@ -192,7 +190,6 @@ export class AnalyticsDemoComponent {
selectPreset(preset: AnalyticsPreset): void {
this.activeId = preset.id;
this.pivot = preset.pivot;
this.nestedRows = (preset.pivot?.rows.length ?? 0) > 1;
this.isPivoted = preset.pivot != null;
this.activeDescription = preset.description;
}
Expand All @@ -202,7 +199,6 @@ export class AnalyticsDemoComponent {
}
}


// analytics.demo-data.ts
import type { PivotConfig, AngularColumnDef, Row } from "@simple-table/angular";

Expand Down Expand Up @@ -390,8 +386,8 @@ export const analyticsPresets: AnalyticsPreset[] = [
},
},
{
id: "nested-rows",
label: "Region Product",
id: "multi-rows",
label: "Region × Product",
description: "Drill into products within each region",
pivot: {
rows: ["region", "product"],
Expand Down
255 changes: 36 additions & 219 deletions apps/marketing/public/txt-demos/angular/pivot.txt
Original file line number Diff line number Diff line change
@@ -1,238 +1,55 @@
// pivot-demo.component.ts
import { Component, Input } from "@angular/core";
import { SimpleTableComponent } from "@simple-table/angular";
import type { AngularColumnDef, PivotConfig, Row, Theme } from "@simple-table/angular";
import { pivotDemoConfig, pivotPresets, type PivotPreset } from "./pivot.demo-data";
import type {
AngularColumnDef,
GetRowIdParams,
PivotConfig,
Theme,
} from "@simple-table/angular";
import { pivotDemoConfig } from "./pivot.demo-data";
import type { PivotFact } from "./pivot.demo-data";
import "@simple-table/angular/styles.css";

@Component({
selector: "pivot-demo",
standalone: true,
imports: [SimpleTableComponent],
template: `
<div style="display: flex; flex-direction: column; gap: 12px; width: 100%">
<div style="display: flex; flex-wrap: wrap; gap: 8px">
@for (preset of presets; track preset.id) {
<button
type="button"
(click)="selectPreset(preset)"
[style.padding]="'6px 12px'"
[style.borderRadius]="'6px'"
[style.border]="'none'"
[style.cursor]="'pointer'"
[style.fontSize]="'13px'"
[style.fontWeight]="500"
[style.background]="preset.id === activeId ? '#2563eb' : '#e5e7eb'"
[style.color]="preset.id === activeId ? '#fff' : '#374151'"
>
{{ preset.label }}
</button>
}
</div>
<simple-table
[rows]="rows"
[columns]="headers"
[pivot]="pivot"
[columnResizing]="true"
[expandAll]="nestedRows"
[height]="height"
[selectableCells]="true"
[theme]="theme"
></simple-table>
</div>
<simple-table
[getRowId]="getRowId"
[rows]="rows"
[columns]="headers"
[pivot]="pivot"
[onPivotChange]="onPivotChange"
[autoExpandColumns]="true"
[columnResizing]="true"
[enableColumnEditor]="true"
[enableColumnEditorInitOpen]="true"
[enablePivotPanel]="true"
[height]="height"
[selectableCells]="true"
[theme]="theme"
></simple-table>
`,
})
export class PivotDemoComponent {
@Input() height: string | number = "400px";
@Input() height: string | number = "500px";
@Input() theme?: Theme;

readonly rows: Row[] = pivotDemoConfig.rows;
readonly headers: AngularColumnDef[] = pivotDemoConfig.headers;
readonly presets = pivotPresets;
readonly rows: PivotFact[] = pivotDemoConfig.rows;
readonly headers: AngularColumnDef<PivotFact>[] = pivotDemoConfig.headers;

activeId = pivotPresets[0].id;
pivot: PivotConfig = pivotPresets[0].pivot;
nestedRows = pivotPresets[0].pivot.rows.length > 1;
pivot: PivotConfig | null = {
rows: ["region", "product"],
columns: ["quarter"],
values: [{ accessor: "sales", aggregation: { type: "sum" } }],
};

selectPreset(preset: PivotPreset): void {
this.activeId = preset.id;
this.pivot = preset.pivot;
this.nestedRows = preset.pivot.rows.length > 1;
}
}


// pivot.demo-data.ts
import type { PivotConfig, AngularColumnDef, Row } from "@simple-table/angular";

export const pivotHeaders: AngularColumnDef[] = [
{ accessor: "region", label: "Region", width: 110, type: "string" },
{ accessor: "country", label: "Country", width: 100, type: "string" },
{ accessor: "category", label: "Category", width: 110, type: "string" },
{ accessor: "product", label: "Product", width: 120, type: "string" },
{ accessor: "channel", label: "Channel", width: 100, type: "string" },
{ accessor: "year", label: "Year", width: 80, type: "number" },
{ accessor: "quarter", label: "Quarter", width: 80, type: "string" },
{
accessor: "sales",
label: "Sales",
width: 100,
type: "number",
align: "right",
valueFormatter: ({ value }) =>
typeof value === "number" ? `$${value.toLocaleString()}` : "",
},
{
accessor: "units",
label: "Units",
width: 80,
type: "number",
align: "right",
},
{
accessor: "cost",
label: "Cost",
width: 100,
type: "number",
align: "right",
valueFormatter: ({ value }) =>
typeof value === "number" ? `$${value.toLocaleString()}` : "",
},
];

const REGIONS = ["West", "East", "North", "South"] as const;
const COUNTRIES: Record<(typeof REGIONS)[number], string[]> = {
West: ["USA", "Canada"],
East: ["USA", "UK"],
North: ["Canada", "Sweden"],
South: ["Brazil", "Australia"],
};
const CATEGORIES = ["Hardware", "Software"] as const;
const PRODUCTS: Record<(typeof CATEGORIES)[number], string[]> = {
Hardware: ["Widget", "Gadget", "Sensor"],
Software: ["License", "Subscription"],
};
const CHANNELS = ["Direct", "Partner", "Online"] as const;
const YEARS = [2024, 2025] as const;
const QUARTERS = ["Q1", "Q2", "Q3", "Q4"] as const;
onPivotChange = (next: PivotConfig | null) => {
this.pivot = next;
};

/** Sparse multi-dimension fact cube (~150–250 rows). */
export function generatePivotRows(): Row[] {
const rows: Row[] = [];
let id = 1;
for (const region of REGIONS) {
for (const country of COUNTRIES[region]) {
for (const category of CATEGORIES) {
for (const product of PRODUCTS[category]) {
for (const channel of CHANNELS) {
for (const year of YEARS) {
for (const quarter of QUARTERS) {
if ((id + year + quarter.charCodeAt(1) + channel.length) % 5 !== 0) {
id++;
continue;
}
const base = 40 + ((id * 17) % 90);
rows.push({
id: `r${id}`,
region,
country,
category,
product,
channel,
year,
quarter,
sales: base * 100,
units: base,
cost: Math.round(base * 55),
});
id++;
}
}
}
}
}
}
}
return rows;
getRowId = ({ row }: GetRowIdParams<PivotFact>) =>
row?.id == null ? undefined : String(row.id);
}

export const pivotRows: Row[] = generatePivotRows();

export type PivotPreset = {
id: string;
label: string;
pivot: PivotConfig;
};

export const pivotPresets: PivotPreset[] = [
{
id: "region-quarter",
label: "Region × Quarter",
pivot: {
rows: ["region"],
columns: ["quarter"],
values: [{ accessor: "sales", aggregation: { type: "sum" } }],
},
},
{
id: "nested-rows",
label: "Region → Product",
pivot: {
rows: ["region", "product"],
columns: ["quarter"],
values: [{ accessor: "sales", aggregation: { type: "sum" } }],
},
},
{
id: "category-year-quarter",
label: "Category × Year → Quarter",
pivot: {
rows: ["category"],
columns: ["year", "quarter"],
values: [{ accessor: "sales", aggregation: { type: "sum" } }],
},
},
{
id: "channel-quarter",
label: "Channel × Quarter",
pivot: {
rows: ["channel"],
columns: ["quarter"],
values: [
{ accessor: "sales", aggregation: { type: "sum" }, label: "Sales" },
{ accessor: "units", aggregation: { type: "sum" }, label: "Units" },
],
},
},
{
id: "country-category",
label: "Country × Category",
pivot: {
rows: ["country"],
columns: ["category"],
values: [{ accessor: "sales", aggregation: { type: "average" } }],
showColumnTotals: false,
},
},
{
id: "values-only",
label: "Values only",
pivot: {
rows: ["region", "category"],
columns: [],
values: [
{ accessor: "sales", aggregation: { type: "sum" } },
{ accessor: "cost", aggregation: { type: "sum" } },
],
},
},
];

export const pivotConfig: PivotConfig = pivotPresets[0].pivot;

export const pivotDemoConfig = {
headers: pivotHeaders,
rows: pivotRows,
tableProps: { pivot: pivotConfig },
presets: pivotPresets,
};
3 changes: 0 additions & 3 deletions apps/marketing/public/txt-demos/react/analytics.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const AnalyticsDemo = ({
const [searchText, setSearchText] = useState("");
const active = analyticsPresets.find((p) => p.id === activeId) ?? analyticsPresets[0];
const isPivoted = active.pivot != null;
const nestedRows = (active.pivot?.rows.length ?? 0) > 1;
const isDark = theme === "dark" || theme === "modern-dark";
const tableHostRef = useRef<HTMLDivElement>(null);
const tableRef = useRef<TableAPI>(null);
Expand Down Expand Up @@ -178,8 +177,6 @@ const AnalyticsDemo = ({
copyHeadersToClipboard
columns={analyticsDemoConfig.headers}
enableColumnEditor
enableStickyParents={nestedRows}
expandAll={nestedRows}
getRowId={({ row }) => String(row.id)}
height={tableHeightPx}
includeHeadersInCSVExport
Expand Down
Loading
Loading