Skip to content

Commit 217ea41

Browse files
author
Timothy Dodd
committed
Enhance dropdown and filter component styling
- Introduced shared global classes for dropdown and filter components in _dropdowns.scss to promote consistency and reusability. - Updated dropdown.component.scss to utilize new global classes, reducing duplication of styles. - Refactored time-filter-dropdown and log-filter-controls components to leverage shared styles, improving maintainability. - Implemented best practices for component styling, including the use of global classes and avoiding @extend. - Added slide-down animation for dropdowns and improved scrollbar styling for better user experience.
1 parent 8092737 commit 217ea41

8 files changed

Lines changed: 484 additions & 399 deletions

File tree

CLAUDE.md

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,137 @@ Use provided mixins for consistent styling:
406406

407407
This styling system ensures a consistent, maintainable, and accessible dark theme throughout the LogMk application while supporting full-width layouts optimized for log monitoring workflows.
408408

409+
### **Shared Component Styling Guidelines**
410+
411+
**Global Style Classes for Component Reuse:**
412+
When creating new components, always check `src/styles/_dropdowns.scss` for existing reusable classes before writing component-specific styles. This file contains common patterns extracted from dropdown and filter components.
413+
414+
**Available Global Classes:**
415+
```scss
416+
// Dropdown and menu styling
417+
.dropdown-menu-base // Base dropdown menu with positioning and styling
418+
.dropdown-item-base // Standard dropdown item with hover states
419+
.category-header-base // Collapsible category headers with icons
420+
.custom-scrollbar // Consistent scrollbar styling for lists
421+
422+
// Form controls and inputs
423+
.search-input-base // Standard search input with focus states
424+
.search-wrapper-base // Search wrapper with icon positioning
425+
.compact-control // Compact sizing (32px height) for filter controls
426+
427+
// Buttons and actions
428+
.action-btn-base // Standard action button with hover/active/disabled states
429+
.count-badge-base // Circular count badges for quantities
430+
.tag-base // Selected item tags with remove functionality
431+
432+
// Layout utilities
433+
.filter-container-base // Flex container for filter controls
434+
.slide-down // Slide-down animation for expanding sections
435+
```
436+
437+
**Component Styling Best Practices:**
438+
```scss
439+
// ✅ Prefer global classes over component-specific styles
440+
.my-component {
441+
.search-section {
442+
@extend .search-wrapper-base; // Use global class
443+
}
444+
445+
.action-button {
446+
@extend .action-btn-base; // Use global class
447+
// Add only component-specific overrides if needed
448+
width: 100px;
449+
}
450+
}
451+
452+
// ❌ Avoid duplicating common patterns
453+
.my-component {
454+
.search-input {
455+
background: var(--input-bg); // This is already in .search-input-base
456+
color: var(--on-surface); // Duplicate styling
457+
border: 1px solid var(--border-color);
458+
// ... more duplicate code
459+
}
460+
}
461+
```
462+
463+
**Creating New Shared Styles:**
464+
When you notice styling patterns being duplicated across 2+ components:
465+
466+
1. **Extract to `_dropdowns.scss`** (or create new shared file if different domain)
467+
2. **Create reusable classes** (not mixins) for direct component usage
468+
3. **Use mixins only** for patterns that need customization parameters
469+
4. **Update this documentation** with new available classes
470+
471+
**Style Architecture Philosophy:**
472+
- **Global classes for common patterns** - Direct usage in components
473+
- **Mixins for customizable patterns** - When parameters are needed
474+
- **Component styles for unique behavior** - Only what's truly component-specific
475+
- **CSS variables for all colors** - Never hardcode colors or spacing
476+
477+
### **Implementation Best Practices**
478+
479+
**Template Class Usage:**
480+
Always apply global classes directly in HTML templates, never use `@extend` in component SCSS:
481+
482+
```html
483+
<!-- ✅ Correct: Direct class usage in template -->
484+
<div class="dropdown-panel dropdown-menu-base">
485+
<input class="search-input search-input-base compact-control" />
486+
<button class="clear-btn action-btn-base" />
487+
</div>
488+
489+
<!-- ❌ Avoid: Using @extend in component SCSS -->
490+
<!-- This requires separate CSS rules instead of direct class usage -->
491+
```
492+
493+
**Component SCSS Override Pattern:**
494+
Use global classes as selectors for component-specific overrides:
495+
496+
```scss
497+
// ✅ Correct: Override global classes for component-specific styling
498+
.search-input-base {
499+
&.filter-search {
500+
width: 100%;
501+
padding-left: 28px; // Space for icon
502+
}
503+
}
504+
505+
.action-btn-base {
506+
&.clear-filters-btn {
507+
width: 32px;
508+
height: 32px;
509+
}
510+
}
511+
512+
// ❌ Avoid: Using @extend in component SCSS
513+
.filter-search {
514+
@extend .search-input-base; // Don't do this
515+
width: 100%;
516+
}
517+
```
518+
519+
**Multi-Class Approach:**
520+
Combine global base classes with modifier classes for different variants:
521+
522+
```html
523+
<!-- Base functionality + size modifier + component-specific -->
524+
<input class="search-input search-input-base compact-control" />
525+
526+
<!-- Base functionality + component-specific styling -->
527+
<button class="action-btn action-btn-base clear-filters-btn" />
528+
529+
<!-- Base + multiple modifiers -->
530+
<div class="dropdown-item dropdown-item-base action-item" />
531+
```
532+
533+
**Benefits of This Approach:**
534+
- **Performance**: No CSS inheritance overhead from `@extend`
535+
- **Transparency**: Easy to see which global classes are used in templates
536+
- **Maintainability**: Global class changes automatically affect all components
537+
- **Debugging**: Clear class names in DevTools for easier inspection
538+
- **Consistency**: Enforces consistent styling patterns across components
539+
409540
## Advanced Features & Services
410541

411542
### **Real-time Log Processing**

src/LogMkWeb/src/app/_components/dropdown/dropdown.component.scss

Lines changed: 12 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -42,43 +42,13 @@
4242
flex-wrap: wrap;
4343
gap: 0.25rem;
4444

45-
.tag {
46-
display: inline-flex;
47-
align-items: center;
48-
gap: 0.25rem;
49-
background-color: var(--primary);
50-
color: var(--on-primary);
51-
padding: 0.125rem 0.375rem;
52-
border-radius: 4px;
53-
font-size: 0.75rem;
54-
font-weight: 500;
55-
56-
lucide-icon {
57-
cursor: pointer;
58-
opacity: 0.7;
59-
&:hover { opacity: 1; }
60-
}
61-
}
6245
}
6346

6447
.selected-count {
6548
display: flex;
6649
align-items: center;
6750
gap: 0.5rem;
6851

69-
.count-badge {
70-
display: inline-flex;
71-
align-items: center;
72-
justify-content: center;
73-
min-width: 1.5rem;
74-
height: 1.5rem;
75-
background-color: var(--primary);
76-
color: var(--on-primary);
77-
border-radius: 50%;
78-
font-size: 0.75rem;
79-
font-weight: 600;
80-
padding: 0 0.25rem;
81-
}
8252

8353
.count-text {
8454
color: var(--on-surface);
@@ -99,18 +69,8 @@
9969
font-size: 0.875rem;
10070
font-weight: 500;
10171

102-
.count-badge {
103-
display: inline-flex;
104-
align-items: center;
105-
justify-content: center;
106-
min-width: 1.5rem;
107-
height: 1.5rem;
108-
background-color: var(--primary);
72+
.count-badge-base {
10973
color: white;
110-
border-radius: 50%;
111-
font-size: 0.75rem;
112-
font-weight: 600;
113-
padding: 0 0.25rem;
11474
}
11575

11676
.count-text {
@@ -136,51 +96,28 @@
13696
}
13797

13898
.dropdown-panel {
139-
@include dropdown-menu;
140-
& {
141-
position: absolute;
142-
top: calc(100% + 4px);
143-
left: 0;
144-
width: max-content;
145-
min-width: 100%;
146-
max-width: 400px;
147-
max-height: 500px;
148-
overflow: visible;
149-
z-index: 1000;
150-
}
99+
width: max-content;
100+
max-width: 400px;
151101
}
152102

153103
.dropdown-search {
154-
display: flex;
155-
align-items: center;
156104
padding: 0.5rem 0.75rem;
157105
border-bottom: 1px solid var(--border-color);
158106
background-color: var(--surface);
159107
position: sticky;
160108
top: 0;
161109
z-index: 10;
162110

163-
.search-icon {
164-
flex-shrink: 0;
165-
color: var(--on-surface-muted);
166-
margin-right: 0.5rem;
167-
}
168-
169-
.search-input {
111+
.input-icon{
112+
flex-shrink: 0;
113+
color: var(--on-surface-muted);
114+
margin-right: .5rem;
115+
}
116+
.search-input-base {
170117
flex: 1;
171-
background: var(--input-bg);
172-
color: var(--on-surface);
173-
border: 1px solid var(--border-color);
174-
border-radius: 4px;
175-
padding: 0.375rem 0.5rem;
176-
font-size: 0.875rem;
177-
outline: none;
178-
transition: all 0.15s ease;
179-
180-
&::placeholder { color: var(--on-surface-muted); }
118+
119+
181120
&:focus {
182-
border-color: var(--primary);
183-
box-shadow: 0 0 0 0.2rem var(--focus-ring);
184121
background-color: var(--surface-variant);
185122
}
186123
}
@@ -208,41 +145,9 @@
208145
max-height: 200px;
209146
overflow-y: auto;
210147
overflow-x: hidden;
211-
212-
&::-webkit-scrollbar {
213-
width: 12px;
214-
background: transparent;
215-
}
216-
217-
&::-webkit-scrollbar-track {
218-
background: var(--surface-variant);
219-
border-radius: 6px;
220-
}
221-
222-
&::-webkit-scrollbar-thumb {
223-
background: var(--border-color);
224-
border-radius: 6px;
225-
border: 2px solid var(--surface-variant);
226-
227-
&:hover { background: var(--on-surface-variant); }
228-
}
229-
230-
scrollbar-width: thin;
231-
scrollbar-color: var(--border-color) var(--surface-variant);
232148
}
233149

234-
.dropdown-item {
235-
display: flex;
236-
align-items: center;
237-
gap: 0.5rem;
238-
padding: 0.5rem 0.75rem;
239-
color: var(--on-surface);
240-
cursor: pointer;
241-
transition: all 0.15s ease;
242-
font-size: 1rem;
243-
244-
&:hover:not(.disabled) { background-color: var(--surface-container); }
245-
150+
.dropdown-item-base {
246151
&.selected:not(.dropdown-container.multiple &) {
247152
background-color: var(--primary);
248153
color: var(--on-primary);
@@ -254,11 +159,6 @@
254159
}
255160
}
256161

257-
&.disabled {
258-
color: var(--disabled-text);
259-
cursor: not-allowed;
260-
}
261-
262162
input[type="checkbox"] {
263163
width: 1rem;
264164
height: 1rem;

0 commit comments

Comments
 (0)