From c8011d7a5be465adf559087b1847393f744ce07a Mon Sep 17 00:00:00 2001 From: Arseniy Klempner Date: Thu, 3 Apr 2025 18:56:12 -0700 Subject: [PATCH] add a theme --- .../src/lib/components/History.svelte | 112 +++++++++++--- .../src/lib/components/HistoryItem.svelte | 132 ++++++++++------- .../lib/components/StateGraphSummary.svelte | 138 +++++++++++++++--- .../sds-demo/src/lib/utils/event.svelte.ts | 16 +- .../src/routes/state-graph/+page.svelte | 125 +++++++++++++--- 5 files changed, 406 insertions(+), 117 deletions(-) diff --git a/examples/sds-demo/src/lib/components/History.svelte b/examples/sds-demo/src/lib/components/History.svelte index dcda668..7364d7e 100644 --- a/examples/sds-demo/src/lib/components/History.svelte +++ b/examples/sds-demo/src/lib/components/History.svelte @@ -166,6 +166,37 @@ overflow-x: hidden; min-width: 400px; scrollbar-width: none; + background-color: #f8f3ff; + border-radius: 12px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + position: relative; + border-left: 4px solid #9966CC; + border-right: 4px solid #9966CC; + padding: 12px; + } + + .history-container::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 6px; + background: linear-gradient(to right, #9966CC, #F59E0B, #9966CC); + border-top-left-radius: 12px; + border-top-right-radius: 12px; + } + + .history-container::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 6px; + background: linear-gradient(to right, #9966CC, #F59E0B, #9966CC); + border-bottom-left-radius: 12px; + border-bottom-right-radius: 12px; } .virtualizer-container { @@ -177,47 +208,78 @@ .header { display: flex; align-items: center; - padding: 8px; + padding: 8px 8px 16px 8px; + border-bottom: 1px solid rgba(107, 79, 138, 0.2); + margin-bottom: 8px; + position: relative; + } + + .header::after { + content: ''; + position: absolute; + left: 10%; + right: 10%; + bottom: -2px; + height: 2px; + background: linear-gradient(90deg, transparent, #F59E0B, transparent); } .help-button { - width: 28px; - height: 28px; + width: 32px; + height: 32px; border-radius: 50%; - background-color: #f3f4f6; - border: 1px solid #d1d5db; - color: #4b5563; + background-color: #F59E0B; + border: 2px solid #FFC107; + color: white; font-weight: bold; font-size: 16px; display: flex; align-items: center; justify-content: center; cursor: pointer; - margin-right: 8px; + margin-right: 12px; transition: all 0.2s; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .help-button:hover { - background-color: #e5e7eb; - color: #1f2937; + background-color: #DB8500; + transform: scale(1.05); } .item-filter { flex: 1; - padding: 8px; - border-radius: 4px; - border: 1px solid #ddd; + padding: 10px 12px; + border-radius: 8px; + border: 2px solid #E0D0FF; + background-color: white; + font-size: 14px; + color: #6B4F8A; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); + appearance: none; + background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236B4F8A' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right 12px center; + background-size: 16px; + transition: all 0.2s; + } + + .item-filter:hover, .item-filter:focus { + border-color: #9966CC; + outline: none; } .id-filter-badge { display: flex; align-items: center; - background-color: #f3f4f6; - border-radius: 16px; - padding: 4px 12px; - margin: 8px; + background: linear-gradient(135deg, #F59E0B 0%, #F59E0B 100%); + border-radius: 20px; + padding: 6px 14px; + margin: 12px 8px; max-width: fit-content; font-size: 12px; + color: white; + box-shadow: 0 2px 6px rgba(245, 158, 11, 0.4); } .id-label { @@ -227,19 +289,29 @@ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; + font-weight: bold; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); } .clear-filter-btn { - background: none; + background: rgba(255, 255, 255, 0.2); border: none; - color: #6b7280; + color: white; font-size: 16px; font-weight: bold; cursor: pointer; - padding: 0 4px; + padding: 0 6px; + border-radius: 50%; + width: 20px; + height: 20px; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s; } .clear-filter-btn:hover { - color: #1f2937; + background: rgba(255, 255, 255, 0.4); + transform: scale(1.1); } diff --git a/examples/sds-demo/src/lib/components/HistoryItem.svelte b/examples/sds-demo/src/lib/components/HistoryItem.svelte index 8e87374..e85bf64 100644 --- a/examples/sds-demo/src/lib/components/HistoryItem.svelte +++ b/examples/sds-demo/src/lib/components/HistoryItem.svelte @@ -2,6 +2,7 @@ import { MessageChannelEvent } from '@waku/sds'; import type { MessageChannelEventObject } from '$lib/sds/stream'; import { getMessageId } from '$lib/sds/message'; + import { eventColors, eventNames } from '$lib/utils/event.svelte'; export let event: MessageChannelEventObject | undefined = undefined; export let identicon: string = ''; @@ -13,30 +14,6 @@ export let overflow: boolean = true; - // Map event types to colors using index signature - const eventColors: { [key in string]: string } = { - [MessageChannelEvent.MessageSent]: '#3B82F6', // blue - [MessageChannelEvent.MessageDelivered]: '#10B981', // green - [MessageChannelEvent.MessageReceived]: '#8B5CF6', // purple - [MessageChannelEvent.MessageAcknowledged]: '#059669', // dark green - [MessageChannelEvent.PartialAcknowledgement]: '#6D28D9', // dark purple - [MessageChannelEvent.MissedMessages]: '#EF4444', // red - [MessageChannelEvent.SyncSent]: '#F59E0B', // orange - [MessageChannelEvent.SyncReceived]: '#F59E0B' // dark orange - }; - - // Event type to display name using index signature - const eventNames: { [key in string]: string } = { - [MessageChannelEvent.MessageSent]: 'Sent', - [MessageChannelEvent.MessageDelivered]: 'Delivered', - [MessageChannelEvent.MessageReceived]: 'Received', - [MessageChannelEvent.MessageAcknowledged]: 'Acknowledged', - [MessageChannelEvent.PartialAcknowledgement]: 'Partially Acknowledged', - [MessageChannelEvent.MissedMessages]: 'Missed', - [MessageChannelEvent.SyncSent]: 'Sync Sent', - [MessageChannelEvent.SyncReceived]: 'Sync Received' - }; - $: id = event ? getMessageId(event) : null; $: color = event ? (eventColors[event.type] || '#888') : '#f0f0f0'; $: name = event ? (eventNames[event.type] || event.type) : ''; @@ -103,6 +80,11 @@ .history-item { padding: 8px; box-sizing: border-box; + transition: transform 0.2s ease; + } + + .history-item:not(.empty):hover { + transform: translateX(2px); } .history-item:not(.empty) { @@ -110,9 +92,9 @@ } .empty { - border: 1px dashed #ccc; - border-radius: 8px; - background-color: #f9f9f9; + border: 1px dashed rgba(107, 79, 138, 0.2); + border-radius: 12px; + background-color: #f8f3ff; } .item-container { @@ -129,14 +111,27 @@ flex-direction: row; align-items: center; justify-content: flex-start; - border-radius: 8px; + border-radius: 12px; width: 100%; min-height: 70px; color: white; - padding: 8px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + padding: 12px; + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.15); position: relative; - transition: box-shadow 0.3s ease; + transition: all 0.3s ease; + border: none; + overflow: hidden; + } + + .event-box::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(45deg, rgba(255,255,255,0.1), rgba(255,255,255,0)); + z-index: 1; } .dependency-box { @@ -149,48 +144,76 @@ min-height: 40px; font-size: 11px; font-family: monospace; - opacity: 0.85; - padding: 6px 12px; - border-radius: 8px; + opacity: 0.9; + padding: 8px 14px; + border-radius: 10px; color: white; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - transition: box-shadow 0.3s ease; + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.15); + transition: all 0.3s ease; overflow: hidden; text-overflow: ellipsis; + position: relative; + } + + .dependency-box::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(45deg, rgba(255,255,255,0.1), rgba(255,255,255,0)); + z-index: 1; } .highlight { - border-left: 4px solid white; - border-right: 4px solid white; + border-left: 4px solid #FFC107; + border-right: 4px solid #FFC107; position: relative; background-image: linear-gradient(rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.1)); + animation: pulse 1.5s infinite; } .highlight .event-type { font-size: 16px; color: white; font-weight: bold; - font-style: italic; letter-spacing: 0.5px; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); } .highlight .event-id, .dependency-box.highlight { font-weight: bold; - font-style: italic; letter-spacing: 0.5px; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); } .dependency-box.highlight { font-size: 12px; } + + @keyframes pulse { + 0% { + box-shadow: 0 0 0 0 rgba(255, 193, 7, 0.7); + } + 70% { + box-shadow: 0 0 0 6px rgba(255, 193, 7, 0); + } + 100% { + box-shadow: 0 0 0 0 rgba(255, 193, 7, 0); + } + } .identicon { width: 40px; height: 40px; - border-radius: 4px; + border-radius: 8px; overflow: hidden; - margin-right: 12px; + margin-right: 14px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + position: relative; + z-index: 2; } .identicon img { @@ -203,6 +226,8 @@ display: flex; flex-direction: column; align-items: flex-start; + position: relative; + z-index: 2; } .event-type { @@ -212,33 +237,42 @@ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); + letter-spacing: 0.05em; } .event-id { font-family: monospace; - font-size: 10px; - color: rgba(255, 255, 255, 0.7); + font-size: 11px; + color: rgba(255, 255, 255, 0.8); max-width: 220px; - /* overflow: hidden; */ text-overflow: ellipsis; white-space: nowrap; } .lamport-timestamp { position: absolute; - top: 8px; - right: 12px; + top: 12px; + right: 14px; font-size: 12px; color: rgba(255, 255, 255, 0.9); font-weight: 500; + background-color: rgba(0, 0, 0, 0.15); + padding: 3px 8px; + border-radius: 10px; + z-index: 2; } .sent-or-received { position: absolute; - top: 8px; - right: 12px; + top: 12px; + right: 14px; font-size: 12px; color: rgba(255, 255, 255, 0.9); font-weight: 500; + background-color: rgba(0, 0, 0, 0.15); + padding: 3px 8px; + border-radius: 10px; + z-index: 2; } \ No newline at end of file diff --git a/examples/sds-demo/src/lib/components/StateGraphSummary.svelte b/examples/sds-demo/src/lib/components/StateGraphSummary.svelte index 77bd484..af380b3 100644 --- a/examples/sds-demo/src/lib/components/StateGraphSummary.svelte +++ b/examples/sds-demo/src/lib/components/StateGraphSummary.svelte @@ -38,13 +38,10 @@ {#each actual_grid as row} {@const length = row.columns.filter((c) => c !== null).length} {@const empty = 4 - length} -
-
-

{row.lamportTimestamp}

- + {@const isEmptyColumn = length === 0} +
+
+ {row.lamportTimestamp}
{#each row.columns as cell} {@const filtered = currentIdFilter.id && cell && matchesIdFilter(cell)} @@ -72,34 +69,110 @@ flex-direction: row; flex-wrap: wrap; justify-content: space-evenly; + gap: 16px; } + + .lamport-timestamp { + text-align: center; + margin-bottom: 8px; + font-weight: bold; + font-size: 14px; + color: #6B4F8A; + position: relative; + } + + .lamport-timestamp::before, + .lamport-timestamp::after { + content: ''; + position: absolute; + height: 2px; + width: 30%; + background: linear-gradient(90deg, transparent, #F59E0B, transparent); + top: 50%; + } + + .lamport-timestamp::before { + left: 5%; + } + + .lamport-timestamp::after { + right: 5%; + } + + .lamport-timestamp span { + background-color: #f8f3ff; + padding: 0 8px; + border-radius: 10px; + position: relative; + z-index: 1; + } + .cell { min-width: 100px; min-height: 50px; - border: 1px solid black; - margin: 1px; - align-content: center; + border: none; + margin: 4px; + border-radius: 6px; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + position: relative; + overflow: hidden; + } + + .cell::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: linear-gradient(45deg, rgba(255,255,255,0.1), rgba(255,255,255,0)); + z-index: 1; } .filtered { + box-shadow: 0 0 0 3px #FFC107; + animation: pulse 1.5s infinite; } .filtered-out { - opacity: 0.3; + opacity: 0.4; } .empty-cell { - /* border: 1px solid black; */ - /* border: none !important; */ + border: 1px dashed rgba(107, 79, 138, 0.2); + background-color: rgba(248, 243, 255, 0.5); + box-shadow: none; } .column { - border: 1px solid black; + border: none; max-height: 400px; - max-width: 280px; min-height: 200px; min-width: 200px; + max-width: 280px; + background-color: #f8f3ff; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + border-radius: 12px; + position: relative; + overflow: hidden; } + + .state-column { + border-left: 4px solid #F59E0B; + border-right: 4px solid #F59E0B; + border-radius: 12px; + transition: transform 0.2s; + background-color: #f8f3ff; + } + + .state-column:hover { + transform: translateY(-4px); + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12); + } + .cell-text { font-size: 12px; text-align: center; @@ -107,17 +180,36 @@ text-transform: uppercase; letter-spacing: 0.1em; color: white; + font-weight: bold; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); + position: relative; + z-index: 2; } - .checkmark-large { - font-size: 24px; - color: transparent; - -webkit-text-stroke: 1px black; + @keyframes pulse { + 0% { + box-shadow: 0 0 0 0 rgba(255, 193, 7, 0.7); + } + 70% { + box-shadow: 0 0 0 6px rgba(255, 193, 7, 0); + } + 100% { + box-shadow: 0 0 0 0 rgba(255, 193, 7, 0); + } } - .checkmark-small { - font-size: 18px; - color: transparent; - -webkit-text-stroke: 1px black; + .empty-column { + background-color: rgba(107, 79, 138, 0.1); + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05); + opacity: 0.8; + } + + .empty-column .lamport-timestamp { + color: rgba(107, 79, 138, 0.6); + } + + .empty-column .empty-cell { + border: 1px dashed rgba(107, 79, 138, 0.15); + background-color: rgba(248, 243, 255, 0.3); } diff --git a/examples/sds-demo/src/lib/utils/event.svelte.ts b/examples/sds-demo/src/lib/utils/event.svelte.ts index 481669b..64ba95f 100644 --- a/examples/sds-demo/src/lib/utils/event.svelte.ts +++ b/examples/sds-demo/src/lib/utils/event.svelte.ts @@ -3,14 +3,14 @@ import { MessageChannelEvent } from '@waku/sds'; import type { MessageChannelEventObject } from '$lib/sds/stream'; export const eventColors: { [key in string]: string } = { - [MessageChannelEvent.MessageSent]: '#3B82F6', // blue - [MessageChannelEvent.MessageDelivered]: '#10B981', // green - [MessageChannelEvent.MessageReceived]: '#8B5CF6', // purple - [MessageChannelEvent.MessageAcknowledged]: '#059669', // dark green - [MessageChannelEvent.PartialAcknowledgement]: '#6D28D9', // dark purple - [MessageChannelEvent.MissedMessages]: '#EF4444', // red - [MessageChannelEvent.SyncSent]: '#F59E0B', // orange - [MessageChannelEvent.SyncReceived]: '#F59E0B' // dark orange + [MessageChannelEvent.MessageSent]: '#427BF5', // bright blue + [MessageChannelEvent.MessageDelivered]: '#10B981', // vibrant green + [MessageChannelEvent.MessageReceived]: '#9966CC', // purple (inspired by image) + [MessageChannelEvent.MessageAcknowledged]: '#3F8C6F', // deeper green + [MessageChannelEvent.PartialAcknowledgement]: '#754FB0', // deep purple + [MessageChannelEvent.MissedMessages]: '#F06060', // coral red (from image) + [MessageChannelEvent.SyncSent]: '#F59E0B', // warm orange (from image) + [MessageChannelEvent.SyncReceived]: '#DB8500' // deeper orange }; // Event type to display name using index signature diff --git a/examples/sds-demo/src/routes/state-graph/+page.svelte b/examples/sds-demo/src/routes/state-graph/+page.svelte index 1db5deb..2740f56 100644 --- a/examples/sds-demo/src/routes/state-graph/+page.svelte +++ b/examples/sds-demo/src/routes/state-graph/+page.svelte @@ -19,30 +19,121 @@ {#if match} -
+
-
+
-
+
-
+
+
+

State Synchronization Visualization

+
{/if} + +