forge
ExploreLog in

Tahinli/forge

public
0 watching
★ 0
3.4 KiB
1// heatmap: sage redesign. See docs in the scratchpad PORT.md brief.
2//
3// The contribution card on the dashboard (views/heatmap.rs). Cells are squares with a 3px gap;
4// the grid lays out seven rows and fills columns, so a week is one column. Colours come from the
5// --h0..--h4 tokens, so both themes follow main.scss.
6//
7// The cell size follows the card: 53 columns fill the card's width, between 11px (then the grid
8// scrolls inside the card) and 16px. The card is a size container, so 100cqi is its width.
9
10$cell: var(--cell);
11$gap: 3px;
12
13.heat {
14 container-type: inline-size;
15 --cell: 11px; // the legend squares; the grid overrides it in .heat-scroll
16 margin-top: 16px;
17 padding: 24px;
18 background: var(--surface);
19 border: 1px solid var(--border);
20 border-radius: var(--radius);
21 min-width: 0;
22
23 h2 {
24 font-size: 18px;
25 }
26}
27
28.heat-head {
29 display: flex;
30 flex-wrap: wrap;
31 gap: 20px 40px;
32 justify-content: space-between;
33 align-items: flex-end;
34 margin-bottom: 22px;
35 min-width: 0;
36}
37
38.heat-stats {
39 display: flex;
40 flex-wrap: wrap;
41 gap: 18px 36px;
42 min-width: 0;
43}
44
45.heat-stat {
46 b {
47 display: block;
48 font-size: 24px;
49 font-weight: 600;
50 line-height: 1.2;
51 letter-spacing: -0.02em;
52 color: var(--text);
53 font-variant-numeric: tabular-nums;
54 }
55
56 b.accent {
57 color: var(--accent-ink);
58 }
59
60 span {
61 font-size: 13px;
62 color: var(--muted);
63 }
64}
65
66// Scrolls sideways inside the card when the 53 columns do not fit (narrow screens).
67// 200px is the label column, the gaps between columns and the padding: 53 cells fill the rest.
68.heat-scroll {
69 --cell: clamp(11px, calc((100cqi - 200px) / 53), 16px);
70
71 overflow-x: auto;
72 padding: 4px 2px 12px;
73 max-width: 100%;
74}
75
76.heat-body {
77 display: grid;
78 grid-template-columns: 32px max-content;
79 column-gap: 8px;
80 width: max-content;
81}
82
83.heat-days {
84 display: grid;
85 grid-template-rows: repeat(7, $cell);
86 row-gap: $gap;
87 margin-top: 18px;
88 font-size: 11px;
89 line-height: $cell;
90 color: var(--muted);
91
92 span {
93 white-space: nowrap;
94 }
95}
96
97// One slot per column, so each label sits over the column where its month starts.
98.heat-months {
99 display: grid;
100 grid-auto-flow: column;
101 grid-auto-columns: $cell;
102 column-gap: $gap;
103 height: 18px;
104 font-size: 12px;
105 line-height: 18px;
106 color: var(--muted);
107
108 span {
109 white-space: nowrap;
110 }
111}
112
113.heat-grid {
114 display: grid;
115 grid-template-rows: repeat(7, $cell);
116 grid-auto-flow: column;
117 grid-auto-columns: $cell;
118 gap: $gap;
119}
120
121.cell {
122 display: block;
123 width: $cell;
124 height: $cell;
125 border-radius: 3px;
126}
127
128.l0 {
129 background: var(--h0);
130}
131
132.l1 {
133 background: var(--h1);
134}
135
136.l2 {
137 background: var(--h2);
138}
139
140.l3 {
141 background: var(--h3);
142}
143
144.l4 {
145 background: var(--h4);
146}
147
148.heat-grid .cell:hover {
149 outline: 1px solid var(--muted);
150 outline-offset: 0;
151}
152
153.cell.blank {
154 visibility: hidden;
155}
156
157.heat-foot {
158 display: flex;
159 flex-wrap: wrap;
160 gap: 12px 24px;
161 justify-content: space-between;
162 align-items: center;
163 margin-top: 8px;
164 min-width: 0;
165
166 p {
167 margin: 0;
168 }
169}
170
171.legend {
172 display: flex;
173 align-items: center;
174 gap: 4px;
175 font-size: 12px;
176 color: var(--muted);
177
178 span:not(.cell) {
179 padding: 0 4px;
180 }
181}
182
183@media (max-width: 600px) {
184 .heat {
185 padding: 18px;
186 }
187
188 .heat-stats {
189 display: grid;
190 grid-template-columns: 1fr 1fr;
191 gap: 16px 24px;
192 width: 100%;
193 }
194
195 .heat-stat b {
196 font-size: 20px;
197 }
198}