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,307 @@
/* ── Mobile Emojis tab ───────────────────────────────────────────────
Full-screen Fluxer-style layout. Uses the same `--background-primary`
page surface and `--background-secondary` rounded cards as the
mobile Roles tab so the two tabs feel like one system. */
.root {
display: flex;
flex-direction: column;
gap: 16px;
}
/* ── Top "Upload Emoji" CTA ─────────────────────────────────────────*/
.uploadButton {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 14px 16px;
background-color: var(--brand-primary);
color: #fff;
border: none;
border-radius: 0.75rem;
font: inherit;
font-size: 16px;
font-weight: 700;
cursor: pointer;
transition: filter 0.15s;
-webkit-tap-highlight-color: transparent;
}
.uploadButton:active:not(:disabled) {
filter: brightness(0.92);
}
.uploadButton:disabled {
opacity: 0.5;
cursor: default;
}
.helperText {
font-size: 13px;
color: var(--text-primary-muted);
line-height: 1.45;
margin: 0 4px;
}
/* ── Upload requirements card ───────────────────────────────────────*/
.sectionLabel {
font-size: 11px;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--text-primary-muted);
padding: 4px 4px 0;
}
.requirementsCard {
background-color: var(--background-secondary);
border-radius: 0.75rem;
padding: 14px 16px;
display: flex;
flex-direction: column;
gap: 10px;
}
.requirementsList {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 8px;
}
.requirementsList li {
font-size: 13px;
color: var(--text-primary);
line-height: 1.45;
padding-left: 16px;
position: relative;
}
.requirementsList li::before {
content: '•';
position: absolute;
left: 0;
color: var(--text-primary-muted);
}
.requirementsList li strong {
font-weight: 700;
}
/* ── Inline upload form (shown when a file is staged) ──────────────*/
.uploadForm {
background-color: var(--background-secondary);
border-radius: 0.75rem;
padding: 14px 16px;
display: flex;
flex-direction: column;
gap: 12px;
}
.uploadFormRow {
display: flex;
align-items: center;
gap: 12px;
}
.uploadPreview {
width: 56px;
height: 56px;
border-radius: 0.5rem;
background-color: var(--background-secondary-alt);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
overflow: hidden;
}
.uploadPreviewImage {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.shortcodeInput {
flex: 1;
background-color: var(--background-secondary-alt);
border: none;
outline: none;
border-radius: 0.5rem;
padding: 10px 12px;
font: inherit;
font-size: 15px;
color: var(--text-primary);
min-width: 0;
}
.shortcodeInput:focus,
.shortcodeInput:focus-visible {
outline: none;
box-shadow: none;
}
.shortcodeInput::placeholder {
color: var(--text-tertiary-muted, var(--text-tertiary));
}
.uploadFormActions {
display: flex;
gap: 8px;
}
.formButton {
flex: 1;
padding: 12px 16px;
border: none;
border-radius: 0.5rem;
font: inherit;
font-size: 14px;
font-weight: 700;
cursor: pointer;
transition: filter 0.15s, background-color 0.15s;
-webkit-tap-highlight-color: transparent;
}
.formButtonPrimary {
background-color: var(--brand-primary);
color: #fff;
}
.formButtonPrimary:disabled {
opacity: 0.5;
cursor: default;
}
.formButtonSecondary {
background-color: var(--background-secondary-alt);
color: var(--text-primary);
}
/* ── Emoji list card ────────────────────────────────────────────────*/
.emojiCard {
background-color: var(--background-secondary);
border-radius: 0.75rem;
overflow: hidden;
}
.emojiRow {
position: relative;
display: grid;
grid-template-columns: 48px 1fr 36px;
align-items: center;
gap: 12px;
padding: 12px 16px;
}
.emojiRow:not(:last-child)::after {
content: '';
position: absolute;
left: calc(16px + 48px + 12px);
right: 16px;
bottom: 0;
height: 1px;
background-color: var(--background-header-secondary);
pointer-events: none;
}
.emojiThumb {
width: 48px;
height: 48px;
border-radius: 0.375rem;
background-color: var(--background-secondary-alt);
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.emojiThumbImage {
max-width: 36px;
max-height: 36px;
object-fit: contain;
}
.emojiName {
font-size: 14px;
font-weight: 600;
color: var(--text-primary);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-width: 0;
}
.deleteButton {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 50%;
border: none;
background: transparent;
color: hsl(350, calc(90% * var(--saturation-factor)), 65%);
cursor: pointer;
-webkit-tap-highlight-color: transparent;
transition: background-color 0.15s;
}
.deleteButton:active {
background-color: var(--background-modifier-hover);
}
.deleteButton:disabled {
opacity: 0.4;
cursor: default;
}
/* ── Empty + status states ─────────────────────────────────────────*/
.empty {
padding: 24px 16px;
text-align: center;
color: var(--text-primary-muted);
font-size: 14px;
}
.status {
padding: 10px 14px;
border-radius: 0.5rem;
font-size: 13px;
}
.statusSuccess {
background-color: hsl(139, calc(47.3% * var(--saturation-factor)), 20%);
color: hsl(139, calc(47.3% * var(--saturation-factor)), 85%);
}
.statusError {
background-color: hsl(0, calc(60% * var(--saturation-factor)), 22%);
color: hsl(0, calc(80% * var(--saturation-factor)), 85%);
}
.gate {
padding: 32px 16px;
text-align: center;
}
.gateTitle {
font-size: 18px;
font-weight: 700;
color: var(--text-primary);
margin: 0 0 8px;
}
.gateBody {
font-size: 14px;
color: var(--text-primary-muted);
margin: 0;
}