v0.23.1 6c872d5

DailyVisitsChart.svelte RawHistoryFolder

1<script lang="ts">
2  import { Chart } from 'frappe-charts';
3  import { onMount } from 'svelte';
4  import type { DailyVisitCount } from '../types';
5
6  interface Props {
7    dailyVisits: DailyVisitCount[];
8  }
9
10  let { dailyVisits }: Props = $props();
11
12  let container: HTMLDivElement;
13  let chart: Chart | null = null;
14
15  // Get accent color from CSS variable
16  function getAccentColor(): string {
17    return getComputedStyle(document.documentElement).getPropertyValue('--primary').trim() || '#4ade80';
18  }
19
20  // Convert data to Frappe Charts format
21  const chartData = $derived.by(() => {
22    if (!dailyVisits || dailyVisits.length === 0) {
23      return { labels: [], datasets: [{ values: [] }] };
24    }
25
26    const labels = dailyVisits.map(d => {
27      const date = new Date(d.day + 'T12:00:00');
28      return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
29    });
30    const values = dailyVisits.map(d => d.visits);
31
32    return {
33      labels,
34      datasets: [{ name: 'Visits', values }]
35    };
36  });
37
38  const totalVisits = $derived(dailyVisits.reduce((sum, d) => sum + d.visits, 0));
39
40  // Initialize chart on mount
41  onMount(() => {
42    if (chartData.labels.length === 0) return;
43
44    chart = new Chart(container, {
45      data: chartData,
46      type: 'line',
47      height: 160,
48      colors: [getAccentColor()],
49      axisOptions: { xAxisMode: 'tick', xIsSeries: true },
50      lineOptions: { regionFill: 1, hideDots: 0, dotSize: 4 },
51      tooltipOptions: { formatTooltipY: (d: number) => `${d} visits` }
52    });
53
54    return () => {
55      chart?.destroy();
56      chart = null;
57    };
58  });
59
60  // Update chart when data changes (after initial mount)
61  $effect(() => {
62    // Skip if chart not initialized yet or no data
63    if (!chart) return;
64
65    // Read chartData to track changes
66    const data = chartData;
67    if (data.labels.length === 0) return;
68
69    chart.update(data);
70  });
71</script>
72
73<div class="chart-wrapper">
74  <div class="chart-header">
75    <span class="chart-label">Visits</span>
76    <span class="chart-value">{totalVisits} total</span>
77  </div>
78  <div bind:this={container} class="chart-container"></div>
79</div>
80
81<style>
82  .chart-wrapper {
83    width: 100%;
84    display: flex;
85    flex-direction: column;
86  }
87
88  .chart-header {
89    display: flex;
90    align-items: center;
91    gap: 0.5rem;
92    padding: 0 0.25rem 0.5rem;
93    font-size: 0.65rem;
94    font-family: ui-monospace, 'Fira Code', 'Cascadia Code', Menlo, Monaco, Consolas, monospace;
95  }
96
97  .chart-label {
98    color: var(--primary, #4ade80);
99    font-weight: 600;
100  }
101
102  .chart-value {
103    color: var(--muted-foreground, #737373);
104  }
105
106  .chart-container {
107    width: 100%;
108  }
109
110  .chart-container :global(.frappe-chart) {
111    font-family: ui-monospace, 'Fira Code', 'Cascadia Code', Menlo, Monaco, Consolas, monospace;
112  }
113
114  .chart-container :global(.frappe-chart .axis text),
115  .chart-container :global(.frappe-chart .chart-label) {
116    fill: var(--muted-foreground, #737373);
117    font-size: 10px;
118  }
119
120  .chart-container :global(.frappe-chart .axis line),
121  .chart-container :global(.frappe-chart .chart-strokes) {
122    stroke: var(--border, #333);
123  }
124</style>

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close