feat(ui): add Button, Modal, Spinner, Toast, and Tooltip components with styles
All checks were successful
Build and Release / build-and-release (push) Successful in 13m12s

- Implemented Button component with various props for customization.
- Created Modal component with header, content, and footer subcomponents.
- Added Spinner component for loading indicators.
- Developed Toast component for displaying notifications.
- Introduced Tooltip component for contextual hints with keyboard shortcuts.
- Added corresponding CSS modules for styling each component.
- Updated index file to export new components.
- Configured TypeScript settings for the UI package.
This commit is contained in:
Bryan1029384756
2026-04-14 09:02:14 -05:00
parent 9ef839938e
commit b7a4cf4ce8
376 changed files with 52619 additions and 167641 deletions

View File

@@ -0,0 +1,173 @@
.container {
padding: 16px 16px 0;
margin-bottom: 8px;
}
.iconWrapper {
width: 68px;
height: 68px;
border-radius: 50%;
background-color: var(--background-modifier-accent);
display: flex;
align-items: center;
justify-content: center;
color: var(--text-primary);
margin-bottom: 8px;
}
.title {
font-size: 2rem;
font-weight: 800;
color: var(--text-primary);
margin: 0 0 8px;
}
.description {
font-size: 0.9375rem;
color: var(--text-secondary);
margin: 0;
line-height: 1.4;
}
/* ── Personal Notes variant ─────────────────────────────────────────
When the channel is the Personal Notes room we render a
centred empty state instead of the left-aligned channel welcome:
a big brand-primary square with the NotePencil icon, the
"Personal Notes" title centred below it, a thin divider, and
the Fluxer-style tagline. Matches the reference screenshot. */
.personalNotesContainer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 48px 32px;
text-align: center;
}
.personalNotesIconWrapper {
width: 72px;
height: 72px;
border-radius: 50%;
background-color: var(--brand-primary);
color: #fff;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16px;
}
.personalNotesTitle {
font-size: 1.75rem;
font-weight: 800;
color: var(--text-primary);
margin: 0 0 12px;
}
.personalNotesDivider {
width: 40px;
height: 2px;
background-color: var(--background-modifier-accent, rgba(255, 255, 255, 0.1));
border-radius: 1px;
margin: 0 0 12px;
}
.personalNotesDescription {
font-size: 0.9375rem;
color: var(--text-primary-muted, var(--text-secondary));
margin: 0;
max-width: 280px;
line-height: 1.4;
}
/* ── 1:1 DM variant ──────────────────────────────────────────────────
Rendered when the channel is a 1:1 DM. Matches the Fluxer mobile
reference: centred layout, large user avatar, username + handle
line, single-line welcome text, and a "Remove Friend" action
button. */
.dmContainer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 48px 32px 24px;
text-align: center;
}
.dmAvatar {
margin-bottom: 18px;
}
.dmNameRow {
display: flex;
align-items: baseline;
gap: 4px;
margin-bottom: 10px;
flex-wrap: wrap;
justify-content: center;
}
.dmName {
font-size: 1.75rem;
font-weight: 800;
color: var(--text-primary);
margin: 0;
}
.dmHandle {
font-size: 1.125rem;
font-weight: 600;
color: var(--text-primary-muted, var(--text-secondary));
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
.dmDescription {
font-size: 0.9375rem;
color: var(--text-primary-muted, var(--text-secondary));
margin: 0 0 18px;
line-height: 1.5;
max-width: 320px;
}
.dmDescription strong {
color: var(--text-primary);
font-weight: 700;
}
.removeFriendButton {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 10px 18px;
background-color: var(--background-secondary-alt);
border: none;
border-radius: 0.5rem;
color: var(--text-primary);
font: inherit;
font-size: 14px;
font-weight: 700;
cursor: pointer;
transition: background-color 0.15s;
-webkit-tap-highlight-color: transparent;
}
.removeFriendButton:hover,
.removeFriendButton:active {
background-color: var(--background-modifier-hover);
}
.removeFriendButton:disabled {
opacity: 0.55;
cursor: default;
}
.dmStatus {
margin-top: 10px;
font-size: 12px;
color: var(--text-primary-muted, var(--text-secondary));
}
.dmStatusError {
color: hsl(0, calc(80% * var(--saturation-factor)), 70%);
}