Skip to content

Commit 483c58d

Browse files
committed
feat(ui): add brutal tooltip component and integrate in settings and docs
1 parent 181ef84 commit 483c58d

5 files changed

Lines changed: 236 additions & 1 deletion

File tree

docs/styles.css

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,123 @@ section {
155155
box-shadow: 3px 3px 0px 0px var(--color-limitra-light);
156156
}
157157

158+
/* --- Tooltip --- */
159+
160+
.brutal-tooltip {
161+
--tooltip-bg: #7c3aed;
162+
--tooltip-text: #ffffff;
163+
--tooltip-border: #171717;
164+
165+
position: relative;
166+
width: fit-content;
167+
cursor: help;
168+
}
169+
170+
html.dark .brutal-tooltip {
171+
--tooltip-border: #fafafa;
172+
}
173+
174+
.brutal-tooltip[data-tooltip]::before {
175+
content: attr(data-tooltip);
176+
}
177+
178+
.brutal-tooltip::before,
179+
.brutal-tooltip .tooltip-content {
180+
visibility: hidden;
181+
width: max-content;
182+
max-width: 250px;
183+
background-color: var(--tooltip-bg);
184+
color: var(--tooltip-text);
185+
text-align: center;
186+
padding: 8px 12px;
187+
border: 2px solid var(--tooltip-border);
188+
box-shadow: 4px 4px 0px 0px var(--tooltip-border);
189+
font-family: 'JetBrains Mono', monospace;
190+
font-size: 12px;
191+
font-weight: 700;
192+
letter-spacing: normal;
193+
line-height: 1.4;
194+
195+
position: absolute;
196+
bottom: calc(100% + 10px);
197+
left: 50%;
198+
transform: translateX(-50%);
199+
z-index: 1002;
200+
201+
opacity: 0;
202+
transition:
203+
opacity 0.2s,
204+
transform 0.2s;
205+
pointer-events: none;
206+
}
207+
208+
.brutal-tooltip .tooltip-content {
209+
position: absolute;
210+
}
211+
212+
.brutal-tooltip::after {
213+
content: '';
214+
position: absolute;
215+
width: 12px;
216+
height: 12px;
217+
218+
background-color: var(--tooltip-border);
219+
border-bottom: 2px solid var(--tooltip-border);
220+
border-right: 2px solid var(--tooltip-border);
221+
222+
transform: translateX(-50%) rotate(45deg);
223+
left: 50%;
224+
bottom: calc(100% + 5px);
225+
226+
z-index: 1001;
227+
opacity: 0;
228+
transition:
229+
opacity 0.2s,
230+
transform 0.2s;
231+
pointer-events: none;
232+
}
233+
234+
.brutal-tooltip:hover::before,
235+
.brutal-tooltip:hover::after,
236+
.brutal-tooltip:hover .tooltip-content {
237+
visibility: visible;
238+
opacity: 1;
239+
}
240+
241+
.brutal-tooltip:hover::before,
242+
.brutal-tooltip:hover .tooltip-content {
243+
transform: translateX(-50%) translateY(-4px);
244+
}
245+
246+
.brutal-tooltip:hover::after {
247+
transform: translateX(-50%) translateY(-4px) rotate(45deg);
248+
}
249+
250+
.brutal-tooltip.tooltip-bottom:hover::before,
251+
.brutal-tooltip.tooltip-bottom:hover .tooltip-content {
252+
transform: translateX(-50%) translateY(4px);
253+
}
254+
255+
.brutal-tooltip.tooltip-bottom:hover::after {
256+
transform: translateX(-50%) translateY(4px) rotate(225deg);
257+
}
258+
259+
.brutal-tooltip.tooltip-bottom::before,
260+
.brutal-tooltip.tooltip-bottom .tooltip-content {
261+
top: calc(100% + 10px);
262+
bottom: auto;
263+
}
264+
265+
.brutal-tooltip.tooltip-bottom::after {
266+
top: calc(100% + 5px);
267+
bottom: auto;
268+
border-bottom: none;
269+
border-right: none;
270+
border-top: 2px solid var(--tooltip-border);
271+
border-left: 2px solid var(--tooltip-border);
272+
transform: translateX(-50%) rotate(45deg);
273+
}
274+
158275
/* --- QR Loader --- */
159276

160277
.qr-loader {

src/ui/components/tooltip.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export function initTooltips(): void {
2+
document.addEventListener('mouseover', (e) => {
3+
const el = (e.target as HTMLElement).closest('.brutal-tooltip') as HTMLElement;
4+
if (!el) return;
5+
6+
const rect = el.getBoundingClientRect();
7+
8+
const spaceAbove = rect.top;
9+
const spaceBelow = window.innerHeight - rect.bottom;
10+
11+
const tooltipHeight = 60;
12+
13+
if (spaceAbove < tooltipHeight && spaceBelow > tooltipHeight) {
14+
el.classList.add('tooltip-bottom');
15+
} else {
16+
el.classList.remove('tooltip-bottom');
17+
}
18+
});
19+
}

src/ui/settings/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
<div class="dashboard-header">
2929
<div class="header-left">
3030
<div class="logo-box">
31-
<div class="logo" title="Limitra">
31+
<div class="logo">
3232
<svg viewBox="0 0 1089 963" class="logo-svg">
3333
<g>
3434
<path

src/ui/settings/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { i18n } from '../../i18n/index';
33
import { LocaleCode } from '../../i18n/types';
44
import { initCustomSelects } from '../components/custom-select';
55
import { showModal } from '../components/modal';
6+
import { initTooltips } from '../components/tooltip';
67

78
function applyTheme(theme: string) {
89
const isPageDark =
@@ -253,6 +254,7 @@ async function init() {
253254
});
254255

255256
initCustomSelects();
257+
initTooltips();
256258
}
257259

258260
void init();

styles.css

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,103 @@ section {
195195
box-shadow: 4px 4px 0px 0px var(--accent);
196196
}
197197

198+
/* --- Tooltip --- */
199+
200+
.brutal-tooltip {
201+
position: relative;
202+
width: fit-content;
203+
cursor: help;
204+
}
205+
206+
.brutal-tooltip[data-tooltip]::before {
207+
content: attr(data-tooltip);
208+
}
209+
210+
.brutal-tooltip::before,
211+
.brutal-tooltip .tooltip-content {
212+
visibility: hidden;
213+
width: max-content;
214+
max-width: 250px;
215+
background-color: var(--accent);
216+
color: var(--text-on-accent);
217+
text-align: center;
218+
padding: 8px 12px;
219+
border: 2px solid var(--ui-border);
220+
box-shadow: 4px 4px 0px 0px var(--ui-border);
221+
font-family: 'JetBrains Mono', monospace;
222+
font-size: 12px;
223+
font-weight: 700;
224+
letter-spacing: normal;
225+
line-height: 1.4;
226+
227+
position: absolute;
228+
bottom: calc(100% + 10px);
229+
left: 50%;
230+
transform: translateX(-50%);
231+
z-index: 1002;
232+
233+
opacity: 0;
234+
transition:
235+
opacity 0.2s,
236+
transform 0.2s;
237+
pointer-events: none;
238+
}
239+
240+
.brutal-tooltip::after {
241+
content: '';
242+
position: absolute;
243+
width: 12px;
244+
height: 12px;
245+
246+
background-color: var(--ui-border);
247+
248+
transform: translateX(-50%) rotate(45deg);
249+
left: 50%;
250+
bottom: calc(100% + 4px);
251+
252+
z-index: 1001;
253+
254+
opacity: 0;
255+
transition: opacity 0.2s;
256+
}
257+
258+
.brutal-tooltip:hover::before,
259+
.brutal-tooltip:hover::after,
260+
.brutal-tooltip:hover .tooltip-content {
261+
visibility: visible;
262+
opacity: 1;
263+
}
264+
265+
.brutal-tooltip:hover::before,
266+
.brutal-tooltip:hover .tooltip-content {
267+
transform: translateX(-50%) translateY(-4px);
268+
}
269+
270+
.brutal-tooltip.tooltip-bottom:hover::before,
271+
.brutal-tooltip.tooltip-bottom:hover .tooltip-content {
272+
transform: translateX(-50%) translateY(4px);
273+
}
274+
275+
.brutal-tooltip:hover::after {
276+
transform: translateX(-50%) translateY(-4px) rotate(45deg);
277+
}
278+
279+
.brutal-tooltip.tooltip-bottom:hover::after {
280+
transform: translateX(-50%) translateY(4px) rotate(225deg);
281+
}
282+
283+
.brutal-tooltip.tooltip-bottom::before,
284+
.brutal-tooltip.tooltip-bottom .tooltip-content {
285+
top: calc(100% + 10px);
286+
bottom: auto;
287+
}
288+
289+
.brutal-tooltip.tooltip-bottom::after {
290+
top: calc(100% + 8px);
291+
bottom: auto;
292+
transform: translateX(-50%) rotate(45deg);
293+
}
294+
198295
/* --- Toggle (brutal-toggle / toggle-slider) --- */
199296

200297
.theme-toggle-btn,

0 commit comments

Comments
 (0)