-
-
Notifications
You must be signed in to change notification settings - Fork 26
refactor(theme): replace C# theme config with a new CSS-first approach #229
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
04db80b
b5e7583
8377257
eaa33e2
ec043c7
db36c90
92ce4a5
b633ce2
3105bcc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| @namespace LumexUI.Docs.Client.Components | ||
| @inherits CodeSnippet | ||
|
|
||
| <div class="group relative" | ||
| data-expanded="@_isExpanded.ToAttributeValue()"> | ||
| <div class="rounded-b-large overflow-hidden group-data-[expanded=false]:max-h-72"> | ||
| @{ | ||
| base.BuildRenderTree( __builder ); | ||
| } | ||
| </div> | ||
|
|
||
| <button type="button" | ||
| class="absolute inset-x-0 bottom-0 flex h-20 items-center justify-center rounded-b-large bg-linear-to-b from-default-800/70 to-default-800 text-default text-small group-data-[expanded=true]:hidden" | ||
| @onclick="@Expand"> | ||
| Expand | ||
| </button> | ||
| </div> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| // Copyright (c) LumexUI 2024 | ||
| // LumexUI licenses this file to you under the MIT license | ||
| // See the license here https://github.com/LumexUI/lumexui/blob/main/LICENSE | ||
|
|
||
| namespace LumexUI.Docs.Client.Components; | ||
|
|
||
| public partial class CodeSnippetCollapsible : CodeSnippet | ||
| { | ||
| private bool _isExpanded; | ||
|
|
||
| private void Expand() | ||
| { | ||
| _isExpanded = true; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,63 +1,57 @@ | ||
| @namespace LumexUI.Docs.Client.Components | ||
| @rendermode InteractiveWebAssembly | ||
|
|
||
| @foreach( var swatch in _swatches ) | ||
| { | ||
| <div class="@(swatch.Title == "Base" ? "order-last sm:order-none" : default)"> | ||
| <div class="font-semibold text-sm text-foreground-900">@swatch.Title</div> | ||
| <div class="grid grid-cols-1 sm:grid-cols-11 mt-3 gap-2.5 sm:mt-2"> | ||
| @foreach( var color in swatch.Scale ) | ||
| <div class="my-10 sm:my-16"> | ||
| <div class="not-prose grid grid-cols-[auto_minmax(0,_1fr)] items-center gap-y-4 gap-x-8"> | ||
| <div class="col-start-2 grid grid-cols-10 justify-items-center gap-1.5 py-1 bg-background font-medium text-small text-foreground-900 *:rotate-180 *:[writing-mode:vertical-lr] sm:gap-4 sm:*:rotate-325 sm:*:[writing-mode:horizontal-tb]"> | ||
| @foreach( var (key, value) in BaseColors ) | ||
| { | ||
| @if( color.Key != "default" && color.Key != "foreground" ) | ||
| { | ||
| var isDivider = color.Key == "divider"; | ||
|
|
||
| <LumexButton Color="@ThemeColor.None" | ||
| Class="w-full min-w-fit h-auto p-0 justify-start gap-x-3 overflow-visible rounded-small sm:block sm:space-y-1"> | ||
| <div class="relative w-12 h-12 rounded-md ring ring-inset ring-foreground-900/15 sm:w-full" | ||
| style="background-color: @(color.Value + (isDivider ? "26" : default))"> | ||
| <div>@value</div> | ||
| } | ||
| </div> | ||
|
|
||
| <span class="absolute top-1 right-1.5 font-medium text-[0.625rem] leading-none" | ||
| style="color: @(isDivider ? "black" : ColorUtils.GetReadableColor(color.Value))"> | ||
| @color.Key | ||
| </span> | ||
| <p class="mb-4 capitalize font-medium text-foreground-900 text-small">Base</p> | ||
| <div class="mb-4 grid grid-cols-10 gap-1.5 sm:gap-4"> | ||
| @foreach( var (key, value) in BaseColors ) | ||
| { | ||
| <div class="aspect-square w-full rounded-sm inset-ring inset-ring-default-900/10 sm:rounded-md" | ||
| style="background-color: var(--color-@key)" /> | ||
| } | ||
| </div> | ||
|
|
||
| @if( swatch.Scale.TryGetValue( "default", out var defValue ) && color.Value == defValue ) | ||
| { | ||
| <span class="absolute top-1 left-1.5 text-[0.625rem] leading-none" | ||
| style="color: @swatch.Scale["foreground"]"> | ||
| ● | ||
| </span> | ||
| } | ||
| </div> | ||
| </LumexButton> | ||
| } | ||
| <div class="sticky top-16 z-10 bg-background"> </div> | ||
| <div class="sticky top-16 z-10 col-start-2 grid grid-cols-10 justify-items-center gap-1.5 py-1 bg-background font-medium text-small text-foreground-900 *:rotate-180 *:[writing-mode:vertical-lr] sm:gap-4 sm:*:rotate-0 sm:*:[writing-mode:horizontal-tb]"> | ||
| @foreach( var shade in Shades ) | ||
| { | ||
| <div>@shade</div> | ||
| } | ||
| </div> | ||
|
|
||
| @foreach( var color in Enum.GetValues<ThemeColor>()[1..] ) | ||
| { | ||
| var colorName = color.ToString().ToLower(); | ||
|
|
||
| <p class="capitalize font-medium text-foreground-900 text-small">@colorName</p> | ||
| <div class="grid grid-cols-10 gap-1.5 sm:gap-4"> | ||
| @foreach( var shade in Shades ) | ||
| { | ||
| <div class="aspect-square w-full rounded-sm inset-ring inset-ring-default-900/10 sm:rounded-md" | ||
| style="background-color: var(--color-@colorName-@shade)" /> | ||
| } | ||
| </div> | ||
| } | ||
|
Comment on lines
+29
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainVerify ThemeColor enum usage and improve robustness. Several concerns with the theme colors implementation:
Consider these improvements: +@using LumexUI.Common // or wherever ThemeColor is defined
- @foreach( var color in Enum.GetValues<ThemeColor>()[1..] )
+ @foreach( var color in Enum.GetValues<ThemeColor>().Where(c => c != ThemeColor.None) )Verify the ThemeColor enum definition and ensure it's properly accessible: 🏁 Script executed: #!/bin/bash
# Search for ThemeColor enum definition and its usage
ast-grep --pattern 'enum ThemeColor { $$$ }'
rg -A 10 "enum ThemeColor"Length of output: 669 🏁 Script executed: #!/bin/bash
set -e
# Print the first 50 lines of the Razor component to check existing using directives
sed -n '1,50p' docs/LumexUI.Docs.Client/Components/ColorSwatches.razorLength of output: 2367 #!/bin/bash
set -e
echo "1. Searching for _Imports.razor in docs/LumexUI.Docs.Client:"
find docs/LumexUI.Docs.Client -type f -name '_Imports.razor' -print
echo
echo "2. Displaying contents of docs/LumexUI.Docs.Client/_Imports.razor (if exists):"
if [ -f docs/LumexUI.Docs.Client/_Imports.razor ]; then
sed -n '1,200p' docs/LumexUI.Docs.Client/_Imports.razor
else
echo " _Imports.razor not found in docs/LumexUI.Docs.Client"
fi
echo
echo "3. Searching for GlobalUsings.cs files:"
find . -type f -name 'GlobalUsings.cs' -print
echo
echo "4. Displaying contents of each GlobalUsings.cs (if any):"
for file in $(find . -type f -name 'GlobalUsings.cs'); do
echo "---- $file ----"
sed -n '1,200p' "$file"
done
echo
echo "5. Searching for explicit using of LumexUI.Common.Enums:"
rg "using .*LumexUI\.Common\.Enums" -n || echo " No explicit using found."🏁 Script executed: #!/bin/bash
set -e
echo "1. All _Imports.razor files and their first 200 lines:"
find . -type f -name '_Imports.razor' -print -exec sed -n '1,200p' {} \;
echo
echo "2. All GlobalUsings.cs files and their first 200 lines:"
find . -type f -name 'GlobalUsings.cs' -print -exec sed -n '1,200p' {} \;
echo
echo "3. Razor component imports for ThemeColor:"
rg -n "ThemeColor" -g "docs/LumexUI.Docs.Client/**/*.razor"Length of output: 35253 Fix missing import and brittle ThemeColor iteration in ColorSwatches.razor Several updates to make this more robust:
Locations to update: Proposed changes: // docs/LumexUI.Docs.Client/_Imports.razor
@using LumexUI.Common
+@using LumexUI.Common.Enums
// docs/LumexUI.Docs.Client/Components/ColorSwatches.razor
- @foreach( var color in Enum.GetValues<ThemeColor>()[1..] )
+ @foreach( var color in Enum.GetValues<ThemeColor>().Where(c => c != ThemeColor.None) )
{
- var colorName = color.ToString().ToLower();
+ var colorName = color.ToCssKey(); // use an extension mapping enum → CSS variable key
<p class="capitalize font-medium text-foreground-900 text-small">@colorName</p>
…
}You’ll need to implement something like: namespace LumexUI.Common.Enums
{
public static class ThemeColorExtensions
{
public static string ToCssKey(this ThemeColor color)
=> color switch
{
ThemeColor.LightBlue => "light-blue",
// add any custom mappings here
_ => color.ToString().ToLower()
};
}
}This ensures the enum is imported, the “None” value is excluded explicitly, and CSS-variable names stay correct even for multi-word enums. 🤖 Prompt for AI Agents |
||
| </div> | ||
| } | ||
| </div> | ||
|
|
||
| @code { | ||
| private readonly Swatch[] _swatches = new Swatch[] | ||
| private static readonly int[] Shades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900]; | ||
| private static readonly Dictionary<string, string> BaseColors = new() | ||
| { | ||
| new("Base", [ | ||
| new( "bg", SemanticColors.Light.Background["default"] ), | ||
| new( "text", SemanticColors.Light.Foreground["default"] ), | ||
| new( "overlay", SemanticColors.Light.Overlay["default"] ), | ||
| new( "divider", SemanticColors.Light.Divider["default"] ), | ||
| new( "focus", SemanticColors.Light.Focus["default"] ), | ||
| new( "surface1", SemanticColors.Light.Surface1["default"] ), | ||
| new( "surface2", SemanticColors.Light.Surface2["default"] ), | ||
| new( "surface3", SemanticColors.Light.Surface3["default"] ), | ||
| ]), | ||
| new("Default", SemanticColors.Light.Default), | ||
| new("Primary", SemanticColors.Light.Primary), | ||
| new("Secondary", SemanticColors.Light.Secondary), | ||
| new("Success", SemanticColors.Light.Success), | ||
| new("Warning", SemanticColors.Light.Warning), | ||
| new("Danger", SemanticColors.Light.Danger), | ||
| new("Info", SemanticColors.Light.Info), | ||
| ["background"] = "bg", | ||
| ["foreground"] = "text", | ||
| ["focus"] = "focus", | ||
| ["divider"] = "divider", | ||
| ["surface1"] = "surface1", | ||
| ["surface2"] = "surface2", | ||
| ["surface3"] = "surface3" | ||
| }; | ||
|
|
||
| private record Swatch( string Title, ColorScale Scale ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,8 +24,8 @@ | |
|
|
||
| private readonly Slots _slots = new() | ||
| { | ||
| Preview = "relative p-4 flex flex-wrap items-center gap-4 overflow-x-auto scrollbar-hide", | ||
| PreviewWrapper = "relative p-4 rounded-xl ring ring-foreground-900/10 not-prose", | ||
| Preview = "relative p-4 flex flex-wrap items-center gap-4 overflow-visible scrollbar-hide", | ||
| PreviewWrapper = "relative p-4 rounded-large ring ring-foreground-900/10 not-prose", | ||
|
Comment on lines
+27
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The preview pane earlier used 🤖 Prompt for AI Agents |
||
| Background = "absolute inset-0 [mask-image:radial-gradient(#fff_0%,transparent_100%)]", | ||
| }; | ||
|
|
||
|
|
||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider exposing the expanded state.
The
_isExpandedfield is private, but the Razor component likely needs access to this state for conditional rendering.Or add a public property:
🤖 Prompt for AI Agents