File size: 7,882 Bytes
0798d16
8da8a3a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c352cab
 
8da8a3a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0798d16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>html studio — harvis</title>
<meta name="description" content="Describe a site, let any open-weights model write it, and deploy it to harvis.dev in about two seconds.">
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="app.css">
</head>
<body>

<header class="nav">
  <a class="lockup" href="https://harvis.dev" target="_blank" rel="noopener">
    <span class="mark">[#]</span>
    <span class="wordmark">harvis</span>
  </a>
  <span class="nav-div" aria-hidden="true"></span>
  <span class="nav-title">html studio</span>

  <div class="nav-spacer"></div>

  <div class="auth">
    <button id="signin" class="btn btn-outline btn-sm" type="button">
      <i class="ri-user-line" aria-hidden="true"></i>Sign in with Hugging Face
    </button>
    <button id="tokentoggle" class="btn btn-ghost btn-sm" type="button">
      <i class="ri-key-2-line" aria-hidden="true"></i>Use a token
    </button>
    <div id="whoami" class="whoami" hidden>
      <img id="avatar" alt="" width="22" height="22">
      <span id="username" class="mono"></span>
      <button id="signout" class="btn btn-ghost btn-sm" type="button">Sign out</button>
    </div>
    <button id="theme" class="btn btn-ghost btn-sm btn-icon" type="button" title="Toggle ink / paper theme" aria-label="Toggle theme">
      <i class="ri-contrast-2-line" aria-hidden="true"></i>
    </button>
  </div>
</header>

<div id="tokenrow" class="tokenrow" hidden>
  <label for="token">access token</label>
  <span class="inputwrap">
    <i class="ri-key-2-line" aria-hidden="true"></i>
    <input id="token" type="password" autocomplete="off" spellcheck="false"
           placeholder="hf_… — huggingface.co/settings/tokens">
  </span>
  <button id="tokensave" class="btn btn-secondary btn-sm" type="button">Save</button>
  <span class="hint">Stored in this browser. Sent only to the Hugging Face router.</span>
</div>

<main class="layout">

  <!-- ── controls ───────────────────────────────────────────────── -->
  <aside class="rail">
    <div class="field">
      <label for="model">model</label>
      <span class="selectwrap">
        <select id="model"><option value="">loading…</option></select>
        <span class="caret" aria-hidden="true"></span>
      </span>
      <p class="hint" id="modelhint">Open-weights chat models on the Hugging Face router.</p>
    </div>

    <div class="field field-grow">
      <label for="prompt">describe the site</label>
      <textarea id="prompt" spellcheck="false"
        placeholder="A landing page for a coffee subscription called Ember. Hero with a tagline, three plan cards with prices, an FAQ, and a footer. Warm, generous whitespace, restrained motion."></textarea>
    </div>

    <details class="advanced">
      <summary>advanced</summary>
      <div class="field">
        <label for="system">system prompt</label>
        <textarea id="system" rows="5" spellcheck="false"></textarea>
      </div>
      <div class="field-row">
        <div class="field">
          <label for="temp">temperature <span id="tempval" class="mono-val">0.70</span></label>
          <input id="temp" type="range" min="0" max="1.5" step="0.05" value="0.7">
        </div>
        <div class="field">
          <label for="maxtok">max tokens</label>
          <input id="maxtok" type="number" min="1000" max="128000" step="1000" value="16000">
        </div>
      </div>
    </details>

    <div class="actions">
      <button id="generate" class="btn btn-primary btn-lg btn-full" type="button">
        <i class="ri-terminal-line" aria-hidden="true"></i>Generate
      </button>
      <button id="stop" class="btn btn-secondary btn-lg" type="button" hidden>Stop</button>
    </div>

    <div class="examples">
      <span class="examples-label">try</span>
      <button class="tag" type="button" data-example="A one-page portfolio for a landscape photographer named Ilse Moreau. Full-bleed hero image from picsum.photos, a masonry gallery of 9 photos with a lightbox, a short about section, and a contact form. Minimal, thin serif headings.">portfolio</button>
      <button class="tag" type="button" data-example="A playable Snake game. Canvas-based, arrow keys and swipe support, score and high score persisted, a start overlay, and a monochrome terminal aesthetic.">snake</button>
      <button class="tag" type="button" data-example="A pricing page for a developer tool called Relay. Three tiers with a monthly/annual toggle that recalculates prices, a feature comparison table, and an FAQ. Square corners, one accent colour, mono for every number.">pricing</button>
      <button class="tag" type="button" data-example="A deployment dashboard: four KPI tiles, a line chart of requests over 12 months, and a table of recent deploys with status dots and mono timestamps. Draw charts with inline SVG, no libraries.">dashboard</button>
    </div>
  </aside>

  <!-- ── output ─────────────────────────────────────────────────── -->
  <section class="output">
    <div class="tabs" role="tablist">
      <button class="tab is-active" id="tab-preview" role="tab" aria-selected="true" type="button">preview</button>
      <button class="tab" id="tab-code" role="tab" aria-selected="false" type="button">
        code <span id="bytes" class="meta"></span>
      </button>
      <div class="tabs-spacer"></div>
      <span id="status" class="status"></span>
      <button id="reload" class="btn btn-ghost btn-sm" type="button">
        <i class="ri-refresh-line" aria-hidden="true"></i>Re-render
      </button>
      <button id="download" class="btn btn-ghost btn-sm" type="button">
        <i class="ri-download-2-line" aria-hidden="true"></i>Download
      </button>
    </div>

    <div class="pane pane-preview" id="pane-preview">
      <div class="empty" id="empty">
        <span class="corners" aria-hidden="true"><i></i><i></i><i></i><i></i></span>
        <i class="ri-code-s-slash-line empty-mark" aria-hidden="true"></i>
        <p class="empty-title">Nothing rendered yet.</p>
        <p class="hint">Pick a model, describe the site, then generate.</p>
      </div>
      <iframe id="preview" title="Live preview of the generated site"
              sandbox="allow-scripts allow-modals allow-popups allow-forms allow-pointer-lock allow-downloads"
              hidden></iframe>
    </div>

    <div class="pane pane-code" id="pane-code" hidden>
      <textarea id="code" spellcheck="false" autocomplete="off"
                placeholder="The generated document lands here, and it is editable. Edits re-render and are what gets deployed."></textarea>
    </div>

    <!-- ── deploy ───────────────────────────────────────────────── -->
    <div class="deploybar">
      <button id="deploy" class="btn btn-primary" type="button" disabled>
        <i class="ri-rocket-line" aria-hidden="true"></i><span id="deploylabel">Deploy to harvis.dev</span>
      </button>
      <button id="newsite" class="btn btn-ghost btn-sm" type="button" hidden
              title="Create a new site instead of updating this one">New site</button>
      <div class="deployresult" id="deployresult"></div>
    </div>
  </section>
</main>

<div id="toast" class="toast" role="status" aria-live="polite" hidden>
  <span class="corners" aria-hidden="true"><i></i><i></i><i></i><i></i></span>
  <span id="toastdot" class="dot"></span>
  <span id="toastmsg"></span>
</div>

<script type="module" src="app.js"></script>
</body>
</html>