02798f8858
Form controls were styled "at a distance": Django renders bare <input>/<select>/<textarea>/<label>, so input.css reached in with ID-scoped #add-form descendant rules plus a global form *:disabled rule and .errorlist. The #add-form ID specificity forced state rules to climb, needed :not([data-search-select-search]) carve-outs, and broke on markup changes — it surfaced as the add_purchase Name/related_game fields not reading as disabled. Components now own all form styling via utilities on the elements themselves: - PrimitiveWidgetsMixin stamps INPUT/SELECT/TEXTAREA_CLASS (incl. disabled: variants) onto native widgets by type, skipping SearchSelect (self-styled) and checkboxes. - New FormFields(form, *, extras=...) renders label + control + errors + row layout with their own classes (replaces form.as_div()); the <form> owns its flex layout. extras appends a node into a named field's row (session timestamp buttons). - AddForm/purchase/session render via FormFields; login too — a new LoginForm(PrimitiveWidgetsMixin, AuthenticationForm) styles its inputs and auth.py renders it via FormFields + a StyledButton (was as_table). - input.css loses the entire #add-form block, the global :disabled rule, and .errorlist. State (disabled:) now lives on the element — no specificity wars, no carve-outs, robust to markup edits. Tests: error rendering uses the component class (not .errorlist); add-form labels/inputs carry their own classes; e2e login fixtures click the Login button by text (submit is now a <button>); Name disabled cursor asserted. CLAUDE.md documents the no-styling-at-a-distance + FormFields conventions. 513 passed; lint/format/ts-check clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
180 lines
4.2 KiB
CSS
180 lines
4.2 KiB
CSS
@import 'tailwindcss';
|
|
|
|
@plugin '@tailwindcss/typography';
|
|
@plugin '@tailwindcss/forms';
|
|
@plugin 'flowbite/plugin';
|
|
|
|
@source "../node_modules/flowbite";
|
|
@import "flowbite/src/themes/default";
|
|
|
|
@custom-variant dark (&:is(.dark *));
|
|
|
|
@theme {
|
|
--font-sans:
|
|
IBM Plex Sans, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji',
|
|
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
|
--font-mono:
|
|
IBM Plex Mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
|
'Liberation Mono', 'Courier New', monospace;
|
|
--font-serif:
|
|
IBM Plex Serif, ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif;
|
|
--font-condensed:
|
|
IBM Plex Sans Condensed, ui-sans-serif, system-ui, sans-serif,
|
|
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
|
|
|
--color-accent: #7c3aed;
|
|
--color-background: #1f2937;
|
|
}
|
|
|
|
|
|
/*
|
|
The default border color has changed to `currentcolor` in Tailwind CSS v4,
|
|
so we've added these compatibility styles to make sure everything still
|
|
looks the same as it did with Tailwind CSS v3.
|
|
|
|
If we ever want to remove these styles, we need to add an explicit border
|
|
color utility to any element that depends on these defaults.
|
|
*/
|
|
@layer base {
|
|
*,
|
|
::after,
|
|
::before,
|
|
::backdrop,
|
|
::file-selector-button {
|
|
border-color: var(--color-gray-200, currentcolor);
|
|
}
|
|
}
|
|
|
|
@utility min-w-20char {
|
|
min-width: 20ch;
|
|
}
|
|
|
|
@utility max-w-20char {
|
|
max-width: 20ch;
|
|
}
|
|
|
|
@utility min-w-30char {
|
|
min-width: 30ch;
|
|
}
|
|
|
|
@utility max-w-30char {
|
|
max-width: 30ch;
|
|
}
|
|
|
|
@utility max-w-35char {
|
|
max-width: 35ch;
|
|
}
|
|
|
|
@utility max-w-40char {
|
|
max-width: 40ch;
|
|
}
|
|
|
|
@layer utilities {
|
|
@font-face {
|
|
font-family: 'IBM Plex Mono';
|
|
src: url('fonts/IBMPlexMono-Regular.woff2') format('woff2');
|
|
font-weight: 400;
|
|
font-style: normal;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: 'IBM Plex Sans';
|
|
src: url('fonts/IBMPlexSans-Regular.woff2') format('woff2');
|
|
font-weight: 400;
|
|
font-style: normal;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: 'IBM Plex Serif';
|
|
src: url('fonts/IBMPlexSerif-Regular.woff2') format('woff2');
|
|
font-weight: 400;
|
|
font-style: normal;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: 'IBM Plex Serif';
|
|
src: url('fonts/IBMPlexSerif-Bold.woff2') format('woff2');
|
|
font-weight: 700;
|
|
font-style: normal;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: 'IBM Plex Sans Condensed';
|
|
src: url('fonts/IBMPlexSansCondensed-Regular.woff2') format('woff2');
|
|
font-weight: 400;
|
|
font-style: normal;
|
|
}
|
|
|
|
.responsive-table {
|
|
@apply dark:text-white mx-auto table-fixed;
|
|
}
|
|
|
|
.responsive-table tr:nth-child(even) {
|
|
@apply bg-indigo-100 dark:bg-slate-800;
|
|
}
|
|
|
|
.responsive-table tbody tr:nth-child(odd) {
|
|
@apply bg-indigo-200 dark:bg-slate-900;
|
|
}
|
|
|
|
.responsive-table thead th {
|
|
@apply text-left border-b-2 border-b-slate-500 text-xl;
|
|
}
|
|
|
|
.responsive-table thead th:not(:first-child),
|
|
.responsive-table td:not(:first-child) {
|
|
@apply border-l border-l-slate-500;
|
|
}
|
|
}
|
|
|
|
/* Form controls (incl. disabled state) and form-field markup (labels, errors,
|
|
rows) are styled by utilities on the elements themselves — see
|
|
PrimitiveWidgetsMixin and FormFields. No form styling lives here. */
|
|
|
|
#button-container button {
|
|
@apply mx-1;
|
|
}
|
|
|
|
.basic-button-container {
|
|
@apply flex space-x-2 justify-center;
|
|
}
|
|
|
|
.basic-button {
|
|
@apply inline-block px-6 py-2.5 bg-blue-600 text-white font-medium text-xs leading-tight uppercase rounded-sm shadow-md hover:bg-blue-700 hover:shadow-lg focus:bg-blue-700 focus:shadow-lg focus:outline-hidden focus:ring-0 active:bg-blue-800 active:shadow-lg transition duration-150 ease-in-out;
|
|
}
|
|
|
|
.markdown-content ul {
|
|
list-style-type: disc;
|
|
list-style-position: inside;
|
|
padding-left: 1em;
|
|
}
|
|
|
|
.markdown-content ol {
|
|
list-style-type: decimal;
|
|
list-style-position: inside;
|
|
padding-left: 1em;
|
|
}
|
|
|
|
.markdown-content ul,
|
|
.markdown-content ol {
|
|
list-style-position: outside;
|
|
padding-left: 1em;
|
|
}
|
|
|
|
.markdown-content ul ul,
|
|
.markdown-content ul ol,
|
|
.markdown-content ol ul,
|
|
.markdown-content ol ol {
|
|
list-style-type: circle;
|
|
margin-top: 0.5em;
|
|
margin-bottom: 0.5em;
|
|
padding-left: 1em;
|
|
}
|
|
|
|
@layer utilities {
|
|
.toast-container {
|
|
@apply fixed z-50 flex flex-col items-end bottom-0 right-0 p-4;
|
|
}
|
|
}
|
|
|