Browse Source

feat: Add frontend template components

Add modular HTML templates for better code organization:
- canvas.html: Game canvas and component palette interface
- challenges.html: Challenge selection and requirements panel
- chat.html: Chat interface with WebSocket support structure
- header.html: Reusable header component

These templates provide a foundation for a more modular
frontend architecture and improved user interface.
main
Stephanie Gredell 5 months ago
parent
commit
9bfe098efe
  1. 340
      static/canvas.html
  2. 14
      static/challenges.html
  3. 57
      static/chat.html
  4. 16
      static/header.html

340
static/canvas.html

@ -0,0 +1,340 @@
{{ define "canvas" }}
<div id="canvas-wrapper">
<input type="radio" id="tab1" name="tab" checked>
<input type="radio" id="tab2" name="tab">
<input type="radio" id="tab3" name="tab">
<div class="tabs">
<div class="tab-labels">
<label for="tab1">Requirements</label>
<label for="tab2">Design</label>
<label for="tab3">Metrics</label>
</div>
<!-- Requirements -->
<div id="content1" class="tab-content">
{{ if .Level.InterviewerRequirements }}
<div class="requirements-section">
<h3>Interviewer Requirements</h3>
<ul class="requirements-list">
{{ range .Level.InterviewerRequirements }}
<li class="requirement-item">{{ . }}</li>
{{ end }}
</ul>
</div>
{{ end }}
{{ if .Level.FunctionalRequirements }}
<div class="requirements-section">
<h3>Functional Requirements</h3>
<ul class="requirements-list">
{{ range .Level.FunctionalRequirements }}
<li class="requirement-item">{{ . }}</li>
{{ end }}
</ul>
</div>
{{ end }}
{{ if .Level.NonFunctionalRequirements }}
<div class="requirements-section">
<h3>Non-Functional Requirements</h3>
<ul class="requirements-list">
{{ range .Level.NonFunctionalRequirements }}
<li class="requirement-item">{{ . }}</li>
{{ end }}
</ul>
</div>
{{ end }}
</div>
<!-- Design-->
<div id="content2" class="tab-content">
<div id="sidebar">
<div class="component-icon" draggable="true" data-type="user">
user
</div>
<div class="component-icon" draggable="true" data-type="loadBalancer">
load balancer
</div>
<div class="component-icon" draggable="true" data-type="webserver">
webserver
</div>
<div class="component-icon" draggable="true" data-type="database">
database
</div>
<div class="component-icon" draggable="true" data-type="cache">
cache
</div>
<div class="component-icon" draggable="true" data-type="messageQueue">
message queue
</div>
<div class="component-icon" draggable="true" data-type="cdn">
CDN
</div>
<div class="component-icon" draggable="true" data-type="microservice">
microservice node
</div>
<div class="component-icon" draggable="true" data-type="data pipeline">
data pipeline
</div>
<div class="component-icon" draggable="true" data-type="monitoring/alerting">
monitoring/alerting
</div>
<div class="component-icon" draggable="true" data-type="third party service">
third-party service
</div>
</div>
<div id="canvas-container">
<div id="connection-modal" style="display: none;" class="modal">
<div class="modal-content">
<h3>Create Connection</h3>
<label>
Label:
<input type="text" id="connection-label" value="Read traffic">
</label>
<label>
Protocol:
<select id="connection-protocol">
<option>HTTP</option>
<option>HTTPS</option>
<option>gRPC</option>
<option>WebSocket</option>
<option>GraphQL</option>
<option>Kafka</option>
<option>AMQP</option>
<option>MQTT</option>
<option>SQL</option>
<option>NoSQL</option>
<option>Redis</option>
<option>TLS</option>
</select>
</label>
<label style="margin-top: 10px;">
<input type="checkbox" id="connection-tls">
Enable TLS (encryption)
</label>
<label for="connection-capacity">Capacity Limit (RPS):</label>
<input type="number" id="connection-capacity" value="1000" min="1" />
<div class="modal-actions">
<button id="connection-save">Save</button>
<button id="connection-cancel">Cancel</button>
</div>
</div>
</div>
<div id="canvas-toolbar">
<button id="arrow-tool-btn" class="toolbar-btn">Arrow Tool</button>
</div>
<div id="info-panel">
<div id="constraints-panel">
<div class="panel-title">level constraints</div>
<div class="panel-metric"><span class="label">🎯 target rps:</span> <span
id="constraint-rps">{{.Level.TargetRPS}}</span></div>
<div class="panel-metric"><span class="label"> max p95 latency:</span> <span
id="constraint-latency">{{.Level.MaxP95LatencyMs}}ms</span></div>
<div class="panel-metric"><span class="label">💸 max cost:</span> <span
id="constraint-cost">${{.Level.MaxMonthlyUSD}}</span></div>
<div class="panel-metric"><span class="label">🔒 availability:</span> <span
id="constraint-availability">{{printf "%.2f" .Level.RequiredAvailabilityPct}}%</span>
</div>
</div>
</div>
<svg id="canvas">
<defs>
<marker id="arrowhead-start" markerWidth="10" markerHeight="7" refX="0" refY="3.5" orient="auto"
markerUnits="strokeWidth">
<path d="M10 0 L0 3.5 L10 7" fill="#ccc" />
</marker>
<marker id="arrowhead-end" markerWidth="10" markerHeight="7" refX="10" refY="3.5" orient="auto"
markerUnits="strokeWidth">
<path d="M0 0 L10 3.5 L0 7" fill="#ccc" />
</marker>
</defs>
</svg>
<div id="node-props-panel">
<h3>node properties</h3>
<div id="label-group" data-group="label-group">
<label>label:</label>
<input type="text" name="label" />
</div>
<div id="db-group" class="prop-group" data-group="db-group">
<label>replication factor:<input type="number" name="replication" min="1" step="1" /></label>
</div>
<div id="cache-group" class="prop-group" data-group="cache-group">
<label>cache ttl (secs):<input type="number" name="cacheTTL" min="0" step="60" /></label>
<label>Max Entries: <input name="maxEntries" type="number" /></label>
<label>Eviction Policy:
<select name="evictionPolicy">
<option value="LRU">LRU</option>
<option value="LFU">LFU</option>
<option value="Random">Random</option>
</select>
</label>
</div>
<div id="compute-group" data-group="compute-group" class="prop-group">
<label>CPU Cores:</label>
<input type="number" name="cpu" min="1" />
<label>RAM (GB):</label>
<input type="number" name="ramGb" min="1" />
<label>RPS Capacity:</label>
<input type="number" name="rpsCapacity" min="1" />
<label>Monthly Cost (USD):</label>
<input type="number" name="monthlyCostUsd" min="0" />
</div>
<div id="lb-group" data-group="lb-group" class="prop-group">
<label>Algorithm</label>
<select name="algorithm">
<option value="round-robin">Round Robin</option>
<option value="least-connections">Least Connections</option>
</select>
</div>
<div id="mq-group" data-group="mq-group" class="prop-group">
<label>Queue Capacity (,ax Messages that can be held in que)</label>
<input type="number" name="queueCapacity" min="1" />
<label>Retention Time (seconds)</label>
<input type="number" name="retentionSeconds" min="1" />
</div>
<div id="cdn-group" data-group="cdn-group" class="prop-group">
<label>TTL (seconds)</label>
<input type="number" name="ttl" min="1" />
<label>Geo Replication</label>
<select name="geoReplication">
<option value="global">Global</option>
<option value="regional">Regional</option>
<option value="custom">Custom</option>
</select>
<label>Caching Strategy</label>
<select name="cachingStrategy">
<option value="cache-first">Cache First</option>
<option value="network-first">Network First</option>
<option value="stale-while-revalidate">Stale While Revalidate</option>
</select>
<label>Compression</label>
<select name="compression">
<option value="brotli">Brotli</option>
<option value="gzip">Gzip</option>
<option value="none">None</option>
</select>
<label>HTTP/2 Support</label>
<select name="http2">
<option value="enabled">Enabled</option>
<option value="disabled">Disabled</option>
</select>
</div>
<div id="microservice-group" data-group="microservice-group" class="prop-group">
<label>
Instance Count:
<input type="number" name="instanceCount" value="3" min="1" />
</label>
<label>
CPU (vCPUs):
<input type="number" name="cpu" value="2" min="1" />
</label>
<label>
RAM (GB):
<input type="number" name="ramGb" value="4" min="1" />
</label>
<label>
RPS Capacity:
<input type="number" name="rpsCapacity" value="150" min="1" />
</label>
<label>
Monthly Cost (USD):
<input type="number" name="monthlyUsd" value="18" min="0" step="1" />
</label>
<label>
Scaling Strategy:
<select name="scalingStrategy">
<option value="auto" selected>Auto</option>
<option value="manual">Manual</option>
</select>
</label>
<label>
API Version:
<input type="text" name="apiVersion" value="v1" />
</label>
</div>
<div id="datapipeline-group" data-group="pipeline-group" class="prop-group">
<label>Batch Size</label>
<input type="number" name="batchSize" min="1" />
<label>Schedule</label>
<select name="schedule">
<option value="realtime">Real-time</option>
<option value="hourly">Hourly</option>
<option value="daily">Daily</option>
<option value="weekly">Weekly</option>
</select>
<label>Transformations</label>
<select name="transformations">
<option value="normalize">Normalize</option>
<option value="dedupe">Dedupe</option>
<option value="filter">Filter</option>
<option value="enrich">Enrich</option>
<option value="aggregate">Aggregate</option>
</select>
<label>Destination</label>
<input type="text" name="destination" placeholder="e.g. data warehouse" />
</div>
<div id="monitor-group" data-group="monitor-group" class="prop-group">
<label>Monitoring Tool</label>
<select name="tool">
<option value="Prometheus">Prometheus</option>
<option value="Datadog">Datadog</option>
<option value="New Relic">New Relic</option>
<option value="Grafana Cloud">Grafana Cloud</option>
</select>
<label>Alert Threshold (%)</label>
<input type="number" name="alertThreshold" min="0" max="100" />
</div>
<div id="third-party-group" data-group="third-party-group" class="prop-group">
<label>Provider</label>
<input type="text" name="provider" />
<label>Latency (ms)</label>
<input type="number" name="latency" min="0" />
</div>
<!-- PUT NEW COMPONENTS BEFORE THIS BUTTON -->
<button id="node-props-save" disabled>save</button>
</div>
<div id="bottom-panel">
<button id="run-button" disabled>Test Design</button>
</div>
</div>
</div>
<!-- Metrics-->
<div id="content3" class="tab-content">This is Tab 3 content.</div>
</div>
</div>
</div>
</div>
{{ end }}

14
static/challenges.html

@ -0,0 +1,14 @@
{{ define "challenges" }}
<div id="challenge-container">
<h2 class="sidebar-title">Challenges</h2>
<ul class="challenge-list">
{{range .Levels}}
<li class="challenge-item {{if and (eq .Name $.Level.Name) (eq .Difficulty $.Level.Difficulty)}}active{{end}}">
<div class="challenge-name">{{.Name}}</div>
<div class="challenge-difficulty {{.Difficulty}}">{{.Difficulty}}</div>
</li>
{{end}}
</ul>
</div>
{{ end }}

57
static/chat.html

@ -0,0 +1,57 @@
{{ define "chat" }}
<label for="chat-checkbox">
<div aria-label="Send message" id="start-chat">
<svg class="chat-bubble" width="32" height="32" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg"
fill="none" stroke="white" stroke-width="4">
<path
d="M4 12C4 7.58 8.03 4 13 4h38c4.97 0 9 3.58 9 8v24c0 4.42-4.03 8-9 8H22l-12 12v-12H13c-4.97 0-9-3.58-9-8V12z" />
</svg>
</div>
</label>
<input type="checkbox" name="chat-checkbox" id="chat-checkbox" class="chat-checkbox" />
<div class="chat">
<div id="chat-header">
<p class="chat-title">System Design Assistant</p>
<p class="powered-by">Powered by AI</p>
</div>
<section id="messages">
<p class="me">
1
</p>
<p class="other">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Autem doloremque exercitationem, blanditiis
obcaecati
earum recusandae quia laudantium assumenda nihil mollitia velit eos molestias odio quasi facilis suscipit
rem
nulla sapiente ea voluptatum repudiandae dicta enim ut! Sed perferendis aliquid vel ad incidunt? In sit id
voluptatibus fugit voluptates, architecto sequi.
</p>
<p class="me">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Ex beatae vero sit delectus, rem totam molestias.
Officia, suscipit error. Voluptatibus.
</p>
<div class="loading-indicator">
<div class="loading-dots">
<div class="loading-dot"></div>
<div class="loading-dot"></div>
<div class="loading-dot"></div>
</div>
<span>loading...</span>
</div>
</section>
<footer>
<textarea name="chat-message" placeholder="Type your message here..."></textarea>
<button aria-label="Send message">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round"
d="M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5" />
</svg>
</button>
</footer>
</div>
{{ end }}

16
static/header.html

@ -0,0 +1,16 @@
{{ define "header" }}
<div id="sd-header">
<h1 class="header-text">System Design Game</h1>
{{ if and .Username .Avatar }}
<div class="userbox">
<img src="{{ .Avatar }}" class="avatar" />
<span class="username">{{ .Username }}</span>
</div>
{{ else }}
<a href="/login" id="github-login-btn">
<img src="https://cdn.jsdelivr.net/gh/devicons/devicon/icons/github/github-original.svg" alt="GitHub Logo">
Login with GitHub
</a>
{{ end }}
</div>
{{ end }}
Loading…
Cancel
Save