diff --git a/clips/templates/clips/index.html b/clips/templates/clips/index.html index 4fe4e5e..d73c62e 100644 --- a/clips/templates/clips/index.html +++ b/clips/templates/clips/index.html @@ -20,12 +20,12 @@ and PUTs with ordinary CSRF protection — no endpoint in this app is exempt. arthur - + {% csrf_token %}
- + diff --git a/clips/views.py b/clips/views.py index d54da4d..3c4aad7 100644 --- a/clips/views.py +++ b/clips/views.py @@ -119,10 +119,27 @@ def _crop_blob(chunks): # the page +def _asset_version(relative): + """A static file's modification time, for its URL. + + The stylesheet and the bundle are served with `Last-Modified` and nothing + else, so a browser is free to keep a stale copy on heuristic freshness — and + new JavaScript over an old stylesheet renders a pane the stylesheet has never + heard of as bare elements. A version in the URL makes each edit a new URL.""" + for root in settings.STATICFILES_DIRS: + path = Path(root) / relative + if path.exists(): + return str(int(path.stat().st_mtime)) + return "0" + + def page(request): """The host page. This replaced `frontend/public/index.html` at step 9, and `:dev-http` in shadow-cljs.edn went away with it.""" - return render(request, "clips/index.html") + return render(request, "clips/index.html", { + "css_version": _asset_version("arthur/app.css"), + "js_version": _asset_version("arthur/js/main.js"), + }) # --------------------------------------------------------------------------- diff --git a/static/arthur/app.css b/static/arthur/app.css index e7c9ae8..d996758 100644 --- a/static/arthur/app.css +++ b/static/arthur/app.css @@ -336,31 +336,47 @@ input[type="range"] { width: 100%; accent-color: var(--sel); } overflow: hidden; } -/* One tab per open symbol. Flat, like the pane heads, with the open one lifted - to the palette bar's colour so it reads as the thing the bar below belongs to. */ +/* One tab per open symbol: flat, on the chrome, with the open one marked by the + selection colour underneath rather than by a raised shape. */ .tabs { display: flex; - gap: 1px; - padding: 3px 6px 0; - background: var(--line); + align-items: stretch; + height: 24px; + flex: 0 0 24px; + padding: 0 4px; + background: var(--chrome); + border-bottom: 1px solid var(--line); overflow-x: auto; } .tab { display: flex; align-items: center; - gap: 6px; - padding: 2px 8px; - background: var(--sunk); + gap: 4px; + padding: 0 6px 0 10px; color: var(--dim); - border-radius: 3px 3px 0 0; + border-right: 1px solid var(--hair); cursor: pointer; white-space: nowrap; } -.tab.on { background: var(--chrome); color: var(--fg); } -.tab .close { padding: 0 3px; border: 0; background: none; color: var(--dim); line-height: 1; } -.tab .close:hover { color: var(--fg); } +.tab:hover { color: var(--fg); background: var(--sunk); } +.tab.on { color: var(--fg); background: var(--pane); box-shadow: inset 0 -2px 0 var(--sel); } + +.tab .close { + width: 16px; + height: 16px; + padding: 0; + border: 0; + border-radius: 2px; + background: none; + color: var(--dim); + line-height: 16px; + visibility: hidden; +} + +.tab:hover .close, .tab.on .close { visibility: visible; } +.tab .close:hover { background: var(--hair); color: var(--fg); } .palette-bar { display: flex;