Skip to content

Light Theme#790

Open
mkpuig wants to merge 7 commits intobsv-blockchain:mainfrom
mkpuig:feature/light-theme
Open

Light Theme#790
mkpuig wants to merge 7 commits intobsv-blockchain:mainfrom
mkpuig:feature/light-theme

Conversation

@mkpuig
Copy link
Copy Markdown

@mkpuig mkpuig commented Apr 29, 2026

Light theme screenshots

Dashboard
imatge

Block Explorer
imatge

P2P
imatge
imatge

Peers
imatge

Network
imatge

Admin
imatge

Settings
imatge

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 29, 2026

🤖 Claude Code Review

Status: Complete

This PR implements a light theme for the Teranode dashboard UI. The implementation adds theme toggle functionality, CSS variable-based theming, and comprehensive light mode color definitions.

Issues Found:

  • [Major] Dark theme missing toggle configuration - The toggle component will use incorrect background color in dark mode (see inline comment on toggle/index.svelte:197)
  • [Minor] Formatting issue in light theme file - Missing newline between tab object and default property (see inline comment on light/index.ts:408)

Analysis:

The light theme file (441 lines) uses an inline approach, while the dark theme (95 lines) uses a modular structure with separate component files. This architectural difference is intentional and acceptable, but creates maintenance asymmetry. The theme toggle implementation in the toolbar is clean and functional. All CSS variables appear properly mapped through the setCSSVariablesFromObj utility.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 29, 2026

Benchmark Comparison Report

Baseline: main (unknown)

Current: PR-790 (eebef52)

Summary

  • Regressions: 0
  • Improvements: 0
  • Unchanged: 142
  • Significance level: p < 0.05
All benchmark results (sec/op)
Benchmark Baseline Current Change p-value
_NewBlockFromBytes-4 1.659µ 1.784µ ~ 0.500
SplitSyncedParentMap_SetIfNotExists/256_buckets-4 61.45n 61.39n ~ 0.400
SplitSyncedParentMap_SetIfNotExists/16_buckets-4 61.44n 61.39n ~ 1.000
SplitSyncedParentMap_SetIfNotExists/1_bucket-4 61.44n 61.42n ~ 1.000
SplitSyncedParentMap_ConcurrentSetIfNotExists/256_buckets... 30.23n 29.70n ~ 0.400
SplitSyncedParentMap_ConcurrentSetIfNotExists/16_buckets_... 50.80n 51.61n ~ 0.700
SplitSyncedParentMap_ConcurrentSetIfNotExists/1_bucket_pa... 107.5n 104.9n ~ 0.400
MiningCandidate_Stringify_Short-4 261.6n 261.4n ~ 1.000
MiningCandidate_Stringify_Long-4 1.891µ 1.889µ ~ 0.600
MiningSolution_Stringify-4 969.9n 985.2n ~ 0.700
BlockInfo_MarshalJSON-4 1.747µ 1.761µ ~ 0.400
NewFromBytes-4 127.9n 129.6n ~ 0.200
Mine_EasyDifficulty-4 58.09µ 59.15µ ~ 0.100
Mine_WithAddress-4 4.845µ 4.720µ ~ 0.100
BlockAssembler_AddTx-4 0.02447n 0.02048n ~ 0.200
AddNode-4 9.186 8.619 ~ 0.100
AddNodeWithMap-4 9.002 9.007 ~ 1.000
DirectSubtreeAdd/4_per_subtree-4 59.34n 62.89n ~ 0.700
DirectSubtreeAdd/64_per_subtree-4 29.41n 29.20n ~ 1.000
DirectSubtreeAdd/256_per_subtree-4 27.87n 27.62n ~ 0.400
DirectSubtreeAdd/1024_per_subtree-4 26.50n 26.38n ~ 0.100
DirectSubtreeAdd/2048_per_subtree-4 26.03n 26.04n ~ 1.000
SubtreeProcessorAdd/4_per_subtree-4 312.4n 313.5n ~ 1.000
SubtreeProcessorAdd/64_per_subtree-4 319.1n 315.4n ~ 0.700
SubtreeProcessorAdd/256_per_subtree-4 311.2n 311.7n ~ 0.400
SubtreeProcessorAdd/1024_per_subtree-4 314.3n 312.3n ~ 0.100
SubtreeProcessorAdd/2048_per_subtree-4 314.8n 309.1n ~ 0.100
SubtreeProcessorRotate/4_per_subtree-4 315.4n 311.3n ~ 0.200
SubtreeProcessorRotate/64_per_subtree-4 316.5n 319.4n ~ 0.100
SubtreeProcessorRotate/256_per_subtree-4 314.4n 314.7n ~ 1.000
SubtreeProcessorRotate/1024_per_subtree-4 305.1n 306.9n ~ 1.000
SubtreeNodeAddOnly/4_per_subtree-4 68.30n 68.55n ~ 0.700
SubtreeNodeAddOnly/64_per_subtree-4 41.02n 40.95n ~ 1.000
SubtreeNodeAddOnly/256_per_subtree-4 39.44n 39.42n ~ 0.800
SubtreeNodeAddOnly/1024_per_subtree-4 38.63n 38.79n ~ 0.100
SubtreeCreationOnly/4_per_subtree-4 163.7n 163.7n ~ 0.800
SubtreeCreationOnly/64_per_subtree-4 593.3n 612.1n ~ 1.000
SubtreeCreationOnly/256_per_subtree-4 1.946µ 1.909µ ~ 0.200
SubtreeCreationOnly/1024_per_subtree-4 4.462µ 4.535µ ~ 0.400
SubtreeCreationOnly/2048_per_subtree-4 7.087µ 7.220µ ~ 1.000
SubtreeProcessorOverheadBreakdown/64_per_subtree-4 312.6n 306.1n ~ 0.700
SubtreeProcessorOverheadBreakdown/1024_per_subtree-4 311.8n 312.6n ~ 1.000
ParallelGetAndSetIfNotExists/1k_nodes-4 927.0µ 922.0µ ~ 0.700
ParallelGetAndSetIfNotExists/10k_nodes-4 1.989m 2.001m ~ 0.700
ParallelGetAndSetIfNotExists/50k_nodes-4 9.050m 9.135m ~ 0.700
ParallelGetAndSetIfNotExists/100k_nodes-4 17.74m 17.80m ~ 1.000
SequentialGetAndSetIfNotExists/1k_nodes-4 753.0µ 745.6µ ~ 1.000
SequentialGetAndSetIfNotExists/10k_nodes-4 3.179m 3.089m ~ 0.100
SequentialGetAndSetIfNotExists/50k_nodes-4 11.60m 11.61m ~ 0.400
SequentialGetAndSetIfNotExists/100k_nodes-4 22.58m 21.79m ~ 0.100
ProcessOwnBlockSubtreeNodesParallel/1k_nodes-4 1.008m 1.010m ~ 0.400
ProcessOwnBlockSubtreeNodesParallel/10k_nodes-4 5.166m 5.117m ~ 0.400
ProcessOwnBlockSubtreeNodesParallel/100k_nodes-4 19.96m 19.48m ~ 0.100
ProcessOwnBlockSubtreeNodesSequential/1k_nodes-4 817.4µ 800.0µ ~ 0.100
ProcessOwnBlockSubtreeNodesSequential/10k_nodes-4 6.557m 6.541m ~ 1.000
ProcessOwnBlockSubtreeNodesSequential/100k_nodes-4 41.67m 42.26m ~ 0.400
DiskTxMap_SetIfNotExists-4 4.815µ 3.894µ ~ 0.100
DiskTxMap_SetIfNotExists_Parallel-4 3.735µ 3.751µ ~ 1.000
DiskTxMap_ExistenceOnly-4 415.4n 352.3n ~ 0.200
Queue-4 210.3n 193.7n ~ 0.100
AtomicPointer-4 3.249n 3.243n ~ 0.100
ReorgOptimizations/DedupFilterPipeline/Old/10K-4 987.1µ 883.8µ ~ 0.100
ReorgOptimizations/DedupFilterPipeline/New/10K-4 909.3µ 853.8µ ~ 0.100
ReorgOptimizations/AllMarkFalse/Old/10K-4 137.8µ 123.6µ ~ 0.100
ReorgOptimizations/AllMarkFalse/New/10K-4 64.84µ 64.44µ ~ 0.200
ReorgOptimizations/HashSlicePool/Old/10K-4 76.40µ 67.83µ ~ 0.100
ReorgOptimizations/HashSlicePool/New/10K-4 11.37µ 11.17µ ~ 0.200
ReorgOptimizations/NodeFlags/Old/10K-4 6.113µ 6.321µ ~ 0.100
ReorgOptimizations/NodeFlags/New/10K-4 2.479µ 2.613µ ~ 0.100
ReorgOptimizations/DedupFilterPipeline/Old/100K-4 12.78m 10.45m ~ 0.200
ReorgOptimizations/DedupFilterPipeline/New/100K-4 12.15m 11.85m ~ 0.200
ReorgOptimizations/AllMarkFalse/Old/100K-4 1.248m 1.217m ~ 0.100
ReorgOptimizations/AllMarkFalse/New/100K-4 708.7µ 710.6µ ~ 0.200
ReorgOptimizations/HashSlicePool/Old/100K-4 703.7µ 672.7µ ~ 1.000
ReorgOptimizations/HashSlicePool/New/100K-4 237.9µ 272.7µ ~ 0.700
ReorgOptimizations/NodeFlags/Old/100K-4 57.79µ 55.85µ ~ 1.000
ReorgOptimizations/NodeFlags/New/100K-4 19.52µ 20.70µ ~ 0.100
TxMapSetIfNotExists-4 47.04n 47.93n ~ 0.200
TxMapSetIfNotExistsDuplicate-4 38.96n 38.89n ~ 0.700
ChannelSendReceive-4 608.8n 591.2n ~ 0.200
CalcBlockWork-4 523.8n 524.7n ~ 0.300
CalculateWork-4 702.0n 704.1n ~ 0.400
BuildBlockLocatorString_Helpers/Size_10-4 1.542µ 1.648µ ~ 0.300
BuildBlockLocatorString_Helpers/Size_100-4 12.29µ 12.29µ ~ 0.400
BuildBlockLocatorString_Helpers/Size_1000-4 121.8µ 122.7µ ~ 0.700
CatchupWithHeaderCache-4 103.7m 103.9m ~ 0.100
_prepareTxsPerLevel-4 415.2m 412.5m ~ 0.200
_prepareTxsPerLevelOrdered-4 3.627m 3.521m ~ 0.100
_prepareTxsPerLevel_Comparison/Original-4 426.3m 425.2m ~ 0.400
_prepareTxsPerLevel_Comparison/Optimized-4 3.615m 3.612m ~ 1.000
SubtreeSizes/10k_tx_4_per_subtree-4 1.311m 1.317m ~ 1.000
SubtreeSizes/10k_tx_16_per_subtree-4 313.8µ 312.3µ ~ 0.700
SubtreeSizes/10k_tx_64_per_subtree-4 75.02µ 74.60µ ~ 1.000
SubtreeSizes/10k_tx_256_per_subtree-4 18.73µ 18.89µ ~ 0.200
SubtreeSizes/10k_tx_512_per_subtree-4 9.234µ 9.360µ ~ 0.200
SubtreeSizes/10k_tx_1024_per_subtree-4 4.595µ 4.564µ ~ 0.400
SubtreeSizes/10k_tx_2k_per_subtree-4 2.292µ 2.287µ ~ 1.000
BlockSizeScaling/10k_tx_64_per_subtree-4 73.43µ 73.23µ ~ 1.000
BlockSizeScaling/10k_tx_256_per_subtree-4 18.70µ 18.48µ ~ 0.400
BlockSizeScaling/10k_tx_1024_per_subtree-4 4.578µ 4.613µ ~ 0.700
BlockSizeScaling/50k_tx_64_per_subtree-4 383.7µ 382.1µ ~ 1.000
BlockSizeScaling/50k_tx_256_per_subtree-4 91.80µ 91.74µ ~ 1.000
BlockSizeScaling/50k_tx_1024_per_subtree-4 22.56µ 22.81µ ~ 0.400
SubtreeAllocations/small_subtrees_exists_check-4 153.4µ 152.9µ ~ 0.700
SubtreeAllocations/small_subtrees_data_fetch-4 161.9µ 161.3µ ~ 1.000
SubtreeAllocations/small_subtrees_full_validation-4 316.2µ 318.0µ ~ 1.000
SubtreeAllocations/medium_subtrees_exists_check-4 9.069µ 9.018µ ~ 0.400
SubtreeAllocations/medium_subtrees_data_fetch-4 9.385µ 9.388µ ~ 1.000
SubtreeAllocations/medium_subtrees_full_validation-4 18.50µ 18.42µ ~ 0.400
SubtreeAllocations/large_subtrees_exists_check-4 2.177µ 2.158µ ~ 1.000
SubtreeAllocations/large_subtrees_data_fetch-4 2.302µ 2.271µ ~ 0.200
SubtreeAllocations/large_subtrees_full_validation-4 4.591µ 4.647µ ~ 0.700
_BufferPoolAllocation/16KB-4 3.223µ 3.216µ ~ 1.000
_BufferPoolAllocation/32KB-4 6.957µ 8.550µ ~ 0.100
_BufferPoolAllocation/64KB-4 13.88µ 15.31µ ~ 0.100
_BufferPoolAllocation/128KB-4 28.77µ 27.75µ ~ 0.200
_BufferPoolAllocation/512KB-4 93.30µ 110.74µ ~ 0.100
_BufferPoolConcurrent/32KB-4 17.84µ 17.78µ ~ 1.000
_BufferPoolConcurrent/64KB-4 25.60µ 28.07µ ~ 0.100
_BufferPoolConcurrent/512KB-4 140.1µ 141.6µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/16KB-4 621.0µ 615.0µ ~ 1.000
_SubtreeDeserializationWithBufferSizes/32KB-4 620.6µ 628.3µ ~ 0.700
_SubtreeDeserializationWithBufferSizes/64KB-4 636.0µ 615.8µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/128KB-4 649.9µ 649.4µ ~ 0.700
_SubtreeDeserializationWithBufferSizes/512KB-4 636.3µ 618.9µ ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/16KB-4 36.24m 36.32m ~ 1.000
_SubtreeDataDeserializationWithBufferSizes/32KB-4 35.48m 35.92m ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/64KB-4 36.07m 35.86m ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/128KB-4 35.63m 36.43m ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/512KB-4 35.24m 35.65m ~ 1.000
_PooledVsNonPooled/Pooled-4 829.4n 841.5n ~ 0.100
_PooledVsNonPooled/NonPooled-4 6.302µ 6.728µ ~ 0.700
_MemoryFootprint/Current_512KB_32concurrent-4 7.314µ 7.108µ ~ 0.700
_MemoryFootprint/Proposed_32KB_32concurrent-4 9.032µ 10.267µ ~ 0.100
_MemoryFootprint/Alternative_64KB_32concurrent-4 9.251µ 9.528µ ~ 0.100
StoreBlock_Sequential/BelowCSVHeight-4 322.9µ 325.8µ ~ 0.400
StoreBlock_Sequential/AboveCSVHeight-4 325.2µ 327.3µ ~ 0.400
GetUtxoHashes-4 272.0n 269.8n ~ 0.400
GetUtxoHashes_ManyOutputs-4 46.15µ 50.79µ ~ 0.100
_NewMetaDataFromBytes-4 230.9n 231.2n ~ 0.100
_Bytes-4 612.1n 609.3n ~ 0.700
_MetaBytes-4 564.3n 563.4n ~ 1.000

Threshold: >10% with p < 0.05 | Generated: 2026-05-01 08:35 UTC

@mkpuig mkpuig force-pushed the feature/light-theme branch from 2c8a47a to b82c80f Compare April 29, 2026 19:25
@mkpuig mkpuig force-pushed the feature/light-theme branch from d87ccd0 to 2ba88b4 Compare April 29, 2026 20:23
height: var(--height);

background: #33373c;
background: var(--toggle-bg-color);
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: The light theme now includes a toggle definition (lines 403-407), which will generate the --toggle-bg-color CSS variable correctly.

However, the dark theme is still missing the toggle definition. The dark theme file (ui/dashboard/src/internal/styles/themes/dark/index.ts) does not export or import a toggle theme object, which means the toggle component will use an incorrect background color in dark mode.

Action needed: Add the toggle configuration to the dark theme to match the light theme structure.

@icellan icellan self-requested a review May 1, 2026 07:19
@icellan icellan added the enhancement New feature or request label May 1, 2026
color: '#E4E6EB',
},
},
tab: { default: {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Minor] Formatting issue: missing newline between tab object and default property.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 1, 2026

@oskarszoon oskarszoon requested review from oskarszoon May 1, 2026 11:29
Copy link
Copy Markdown
Contributor

@oskarszoon oskarszoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking bugs

Toggle invisible in dark mode. lib/components/toggle/index.svelte:197 uses var(--toggle-bg-color) with no fallback. Dark theme has no toggle key, so background falls back to transparent. Fix: var(--toggle-bg-color, #33373c) or add toggle key to dark theme.

Settings clear-search invisible on hover. routes/settings/+page.svelte:534-537 sets color: var(--app-color); background-color: var(--app-color) — text and bg same value.

Peers catchup modal hardcoded dark. routes/peers/+page.svelte:1577,1596background: #1a1b23 and #15161d. Dark island in light theme.

Admin scrollbar + refresh-button use text color as background. routes/admin/+page.svelte:1426-1432, 1612background-color: var(--app-color).

P2P peer header still hardcoded white. routes/p2p/+page.svelte:403background: rgba(255, 255, 255, 0.05) not converted.

Untouched, broken in light (call out as follow-up or fix here)

  • internal/components/breadcrumbs/index.svelte:81,85 — every page header
  • internal/components/block-assembly-modal/index.svelte — entire modal
  • internal/components/page/viewer/no-data-card/index.svelte:29,37
  • internal/components/page/home/home-stats-graph/graph.ts:195 — chart axes
  • lib/components/navigation/{drawer,menu-item} — sidenav
  • lib/components/textinput/index.svelte:370
  • routes/{login,wstest}/+page.svelte

Other

FOUC. Removing $theme = 'dark' from +layout.svelte means SSR returns null (browser=false), first paint = light, then snaps to dark. Inline an early script in app.html to set the class before paint.

clearAllCSSVariables then partial set. Causes the toggle bug above. Add CI check that both themes share the same key shape.

Toolbar toggle a11y. Add aria-label and aria-pressed — title attr alone insufficient.

Behaviour change. json-tree boolean color went from CSS blue (#0000FF) to #1a6bd4 in dark — intentional? Note in description.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants