-
By {displayData.subtitle || displayData.user_name || 'Unknown'}
+
By {hero.subtitle || hero.user_name || 'Unknown'}
- {displayData.title}
+ {hero.title}
- {displayData.description}
+ {hero.description}
diff --git a/frontend/src/components/ui/CTASection.svelte b/frontend/src/components/ui/CTASection.svelte
new file mode 100644
index 0000000..045d644
--- /dev/null
+++ b/frontend/src/components/ui/CTASection.svelte
@@ -0,0 +1,55 @@
+
+
+
+
+ {title}
+
+
+ {description}
+
+
+
+ {#if secondaryLinkText && secondaryLinkPath}
+
+ {/if}
+
+
diff --git a/frontend/src/components/ui/ChartPlaceholder.svelte b/frontend/src/components/ui/ChartPlaceholder.svelte
new file mode 100644
index 0000000..6c3e7e9
--- /dev/null
+++ b/frontend/src/components/ui/ChartPlaceholder.svelte
@@ -0,0 +1,13 @@
+
+
+
+
+
+
{title}
+
{subtitle}
+
+
diff --git a/frontend/src/components/ui/HighlightCards.svelte b/frontend/src/components/ui/HighlightCards.svelte
new file mode 100644
index 0000000..6ca6f2c
--- /dev/null
+++ b/frontend/src/components/ui/HighlightCards.svelte
@@ -0,0 +1,109 @@
+
+
+{#if loading}
+
+ {#each [1, 2, 3] as _}
+
+ {/each}
+
+{:else if highlights.length === 0}
+
+
+ No highlights yet
+
+
+{:else}
+
+ {#each highlights as highlight}
+ {@const cat = highlight.contribution_type_category || category}
+ {@const colors = getColors(cat)}
+
+
+
+
+
+
+ {highlight.user_name || `${highlight.user_address?.slice(0, 6)}...`}
+
+
+
+ {formatPoints(highlight.contribution_points)} pts
+
+
+
+
+
+
{highlight.title}
+
+ {highlight.description}
+
+
+
+
+
+
+ {highlight.contribution_type_name || cat}
+
+
+ {formatDate(highlight.contribution_date)}
+
+
+
+ {/each}
+
+{/if}
diff --git a/frontend/src/components/ui/MemberCardScroller.svelte b/frontend/src/components/ui/MemberCardScroller.svelte
new file mode 100644
index 0000000..191b7de
--- /dev/null
+++ b/frontend/src/components/ui/MemberCardScroller.svelte
@@ -0,0 +1,110 @@
+
+
+{#if loading}
+
+ {#each [1, 2, 3, 4, 5, 6, 7, 8] as _}
+
+ {/each}
+
+{:else if members.length === 0}
+
No members yet
+{:else}
+
+ {#each members as member}
+
+ {/each}
+
+{/if}
diff --git a/frontend/src/components/ui/RankedList.svelte b/frontend/src/components/ui/RankedList.svelte
new file mode 100644
index 0000000..6bd7697
--- /dev/null
+++ b/frontend/src/components/ui/RankedList.svelte
@@ -0,0 +1,166 @@
+
+
+
+ {#if loading}
+
+
+
+ {#each [1, 2, 3, 4, 5] as _}
+
+ {/each}
+
+
+ {#each [1, 2, 3, 4, 5] as _}
+
+ {/each}
+
+
+
+ {#each [1, 2, 3, 4, 5] as _}
+
+ {/each}
+
+
+ {:else if entries.length === 0}
+
No data
+ {:else}
+
+
+
+
+
+ {#each entries as _, i}
+
+ {#if i === 0}
+
+
+ {:else if i === 1}
+
+
+ {:else if i === 2}
+
+
+ {:else}
+
{i + 1}
+ {/if}
+
+ {/each}
+
+
+
+ {#each entries as entry}
+
+ {/each}
+
+
+
+
+
+ {#each entries as entry}
+
+ {#if showDelta}
+
+ {/if}
+
{formatPoints(entry.total_points ?? entry.points)}
+
GP
+
+ {/each}
+
+
+ {/if}
+
diff --git a/frontend/src/components/ui/SectionHeader.svelte b/frontend/src/components/ui/SectionHeader.svelte
new file mode 100644
index 0000000..51f50a9
--- /dev/null
+++ b/frontend/src/components/ui/SectionHeader.svelte
@@ -0,0 +1,26 @@
+
+
+
+
+
{title}
+ {#if subtitle}
+
{subtitle}
+ {/if}
+
+ {#if showLink && linkPath}
+
+ {/if}
+
diff --git a/frontend/src/components/ui/StatCardRow.svelte b/frontend/src/components/ui/StatCardRow.svelte
new file mode 100644
index 0000000..f663e09
--- /dev/null
+++ b/frontend/src/components/ui/StatCardRow.svelte
@@ -0,0 +1,65 @@
+
+
+{#if loading}
+
+ {#each Array(columns) as _}
+
+ {/each}
+
+{:else}
+
+ {#each stats as stat}
+
+
+
+ {#if stat.iconSrc}
+

+ {:else}
+
+ {/if}
+
+
+
{formatNumber(stat.value)}
+
{stat.label}
+
+
+ {#if stat.delta}
+
+

+
{formatDelta(stat.delta)}
+
+ {/if}
+
+ {/each}
+
+{/if}
diff --git a/frontend/src/components/ui/UserCardScroller.svelte b/frontend/src/components/ui/UserCardScroller.svelte
new file mode 100644
index 0000000..a8e178d
--- /dev/null
+++ b/frontend/src/components/ui/UserCardScroller.svelte
@@ -0,0 +1,106 @@
+
+
+{#if loading}
+
+ {#each [1, 2, 3, 4, 5, 6] as _}
+
+ {/each}
+
+{:else if entries.length === 0}
+
No contributors yet
+{:else}
+
+ {#each entries as entry}
+
+ {/each}
+
+{/if}
diff --git a/frontend/src/routes/Dashboard.svelte b/frontend/src/routes/Dashboard.svelte
index df99809..84bc1e3 100644
--- a/frontend/src/routes/Dashboard.svelte
+++ b/frontend/src/routes/Dashboard.svelte
@@ -1,369 +1,329 @@
-
-
-
- {$currentCategory === 'builder' ? 'Builders' :
- $currentCategory === 'validator' ? 'Validators' :
- $currentCategory === 'steward' ? 'Stewards' : 'Dashboard'}
-
-
-
- {#if statsError}
-
-
-
-
-
- Having trouble connecting to the API. Some data might not display correctly.
-
-
-
-
- {/if}
+
+
+
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
- Top {$currentCategory === 'builder' ? 'Builders' :
- $currentCategory === 'validator' ? 'Validators' :
- $currentCategory === 'steward' ? 'Stewards' : 'Participants'}
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
Highlighted Contributions
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
- Newest {$currentCategory === 'builder' ? 'Builders' :
- $currentCategory === 'validator' ? 'Validators' :
- $currentCategory === 'steward' ? 'Stewards' : 'Participants'}
-
-
-
-
-
- {#if newestValidatorsLoading}
-
- {:else if newestValidatorsError}
-
-
{newestValidatorsError}
-
- {:else if newestValidators.length === 0}
-
-
No new validators yet.
+
+
+
+
+
+
+
+
+ {#if isBuilder}
+
+ {/if}
+
+
+ {#if isBuilder}
+
+
+
+
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {#if isValidator}
+
+
+
+
- {:else}
-
- {#each newestValidators as validator}
-
-
-
-
+
+
+
+ {#if recentLoading}
+
+ {#each [1, 2, 3, 4, 5] as _}
+
+ {/each}
+
+ {:else if recentContributions.length === 0}
+
No recent contributions
+ {:else}
+
+ {#each recentContributions as contrib}
-
- {formatDate(validator.first_uptime_date || validator.created_at)}
-
-
+ {/each}
-
-
- {/each}
-
- {/if}
-
-
-
-
-
-
-
-
+ {#if isBuilder}
+
-
-
+ {:else}
+
+ {/if}
+
diff --git a/frontend/src/stores/category.js b/frontend/src/stores/category.js
index 68f6cf6..66b3b60 100644
--- a/frontend/src/stores/category.js
+++ b/frontend/src/stores/category.js
@@ -52,7 +52,7 @@ export const categoryTheme = derived(currentCategory, $category => {
},
builder: {
// Orange/sunset theme
- bg: 'bg-orange-50',
+ bg: 'bg-white',
bgSecondary: 'bg-orange-100',
primary: 'bg-orange-500',
primaryHover: 'hover:bg-orange-600',
@@ -67,7 +67,7 @@ export const categoryTheme = derived(currentCategory, $category => {
},
validator: {
// Blue/technical theme
- bg: 'bg-sky-50',
+ bg: 'bg-white',
bgSecondary: 'bg-sky-100',
primary: 'bg-sky-500',
primaryHover: 'hover:bg-sky-600',