oficina / sheets Public

Move rastrillo to amadan.net/rastrillo/rastrillo (v0.23.0 -> 29e4491)

Every import of github.com/carlosframework/rastrillo now names
amadan.net/rastrillo/rastrillo, pinned at 29e4491 (v0.26.0+8), the
version home/connect, home/handoff and the assertion tests already used.
The old path stops at v0.23.0, so Sheets had received no rastrillo fix
since 2026-08-31, iOS's zoom-on-tap fix included.

- tokens.css re-copied by `go tool rastrillo doctor --fix` at that pin:
  the touch rule (16px text controls under a coarse pointer, and
  touch-action: manipulation), button sizes sm/lg/block, --rst-fs-lg,
  primary inputs, the stat band, native meter/progress for meter and
  job-status, and the date picker's calendar styles. The four scripts
  doctor also adds (rastrillo.js, select.js, datetime.js, calendar.js)
  are deleted: Sheets serves estilo's split shim and busy.js, and at
  this pin doctor's shim still carries the old busy rule.
  TestBusyRuleIsLinkedAndServed now fails if one is left on disk.
- One old-path import stays, in native.go: rastrillo/native's server
  takes the old *sessions.Sessions. Both packages share the frozen
  sessions table. TestNoPreMoveRastrillo forbids any other.
- The CLI is a go.mod tool; make test-migrations runs `go tool
  rastrillo`, not whatever is on PATH.
- make release stamps amadan.net/rastrillo/rastrillo.BuildVersion. The
  old symbol would have left /api/version answering "dev".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev c58a414e58682aca47f8944b71270751f324ad33 parent be56866
35 files changed, +426 −59
  • AGENTS.md +13 −0
  • Makefile +8 −2
  • cmd/sheets/main.go +3 −3
  • go.mod +3 −0
  • go.sum +2 −0
  • internal/guardstest/forbidden_imports_test.go +28 −0
  • internal/guardstest/userid_test.go +1 −1
  • internal/sheets/app.go +4 −4
  • internal/sheets/auth.go +2 −2
  • internal/sheets/begin_test.go +2 −2
  • internal/sheets/errors.go +1 −1
  • internal/sheets/handlers_import.go +2 −2
  • internal/sheets/helpers_test.go +2 −2
  • internal/sheets/home.go +2 −2
  • internal/sheets/home_navigation_test.go +1 −1
  • internal/sheets/home_test.go +1 −1
  • internal/sheets/jobpages.go +1 −1
  • internal/sheets/migrations.go +3 −3
  • internal/sheets/native.go +10 −2
  • internal/sheets/render.go +2 −2
  • internal/sheets/signin.go +1 −1
  • internal/sheets/signin_test.go +2 −2
  • internal/sheets/static/tokens.css +303 −6
  • internal/sheets/store/handle_blank_cap_test.go +2 −2
  • internal/sheets/store/handle_blank_crash_test.go +2 −2
  • internal/sheets/store/handle_blank_recovery_bench_test.go +2 −2
  • internal/sheets/store/handle_version_migration_test.go +2 −2
  • internal/sheets/store/helpers_test.go +2 −2
  • internal/sheets/theme_assets_test.go +11 −1
  • internal/sheets/theme_test.go +1 −1
  • internal/sheets/xlsx/blob.go +1 −1
  • internal/sheets/xlsx/blob_test.go +1 −1
  • internal/sheets/xlsx/helpers_test.go +2 −2
  • internal/sheets/xlsx/plaintext_test.go +2 −2
  • internal/sheets/zoom_browser_test.go +1 −1
diff --git a/AGENTS.md b/AGENTS.md
index 09c946d..107a769 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -195,6 +195,19 @@ relying on remembering one, make it a test instead.
- `rst-tone` pairs with `data-tone` rather than with a class.
- Adopt per screen, never per element — mixed spellings inside one
component match neither.
+- **rastrillo is `amadan.net/rastrillo/rastrillo`.** The old path,
+ `github.com/carlosframework/rastrillo`, stops at v0.23.0: code importing
+ it gets no fix, and its own checks cannot tell (Sheets zoomed iOS on
+ every tap for a month that way). `TestNoPreMoveRastrillo` allows one
+ import of it, native.go's bridge to rastrillo/native's server, until
+ that server moves. The CLI is pinned as a `tool` in go.mod: run it as
+ `go tool rastrillo …`, never a `rastrillo` from PATH.
+- **After `go tool rastrillo doctor --fix`, delete the scripts it adds**
+ (`static/rastrillo.js`, `select.js`, `datetime.js`, `calendar.js`).
+ Sheets serves estilo's shim and busy.js from memory and uses no other
+ rastrillo script; the shim doctor adds at this pin still carries the
+ old busy rule, which fights estilo's. `TestBusyRuleIsLinkedAndServed`
+ fails if one is left behind.
- **Run `rastrillo doctor` on every rastrillo upgrade**, and
`rastrillo doctor --fix` to re-copy what drifted. `static/tokens.css` is
frozen at scaffold time while the partials it styles keep upgrading with
diff --git a/Makefile b/Makefile
index 27cf795..b55bd98 100644
--- a/Makefile
+++ b/Makefile
@@ -41,7 +41,7 @@ release:
{ echo "make release: no version to stamp; commit, or name it: make release VERSION=v0.1.0"; exit 1; }
@mkdir -p releases
CGO_ENABLED=0 GOOS=$(RELEASE_GOOS) GOARCH=$(RELEASE_GOARCH) go build -trimpath \
- -ldflags "-s -w -X github.com/carlosframework/rastrillo.BuildVersion=$(VERSION)" \
+ -ldflags "-s -w -X amadan.net/rastrillo/rastrillo.BuildVersion=$(VERSION)" \
-o $(RELEASE_BIN) ./cmd/$(APP)
@echo "built $(RELEASE_BIN) reporting version $(VERSION)"
@echo "publish it with:"
@@ -88,8 +88,14 @@ test-build:
# app is known to compile and well before test-go pays for real SQLite
# files. A model changed without `rastrillo migration generate` run
# after it fails here, not in production at the next boot.
+#
+# `go tool`, not a bare `rastrillo` on PATH: go.mod pins the CLI as a tool
+# at the same version as the module, so the check always runs the
+# migrate the app is built against — never whatever a machine happened
+# to have installed (a v0.25.0 CLI answering for a v0.23.0 app, until
+# the move to amadan.net/rastrillo/rastrillo).
test-migrations:
- rastrillo migration check
+ go tool rastrillo migration check
# Includes internal/guardstest: the mechanical guards for the line cap,
# forbidden imports, excelize confinement, calc isolation and sealtest
diff --git a/cmd/sheets/main.go b/cmd/sheets/main.go
index d050593..68e781d 100644
--- a/cmd/sheets/main.go
+++ b/cmd/sheets/main.go
@@ -28,9 +28,9 @@ import (
"net/http"
"os"
- "github.com/carlosframework/rastrillo"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
"amadan.net/oficina/sheets/internal/sheets"
)
diff --git a/go.mod b/go.mod
index e9c82eb..a2004bd 100644
--- a/go.mod
+++ b/go.mod
@@ -17,6 +17,7 @@ require (
)
require (
+ github.com/BurntSushi/toml v1.6.0 // indirect
github.com/chromedp/sysutil v1.1.0 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
@@ -48,3 +49,5 @@ require (
modernc.org/memory v1.11.0 // indirect
modernc.org/sqlite v1.55.0 // indirect
)
+
+tool amadan.net/rastrillo/rastrillo/cmd/rastrillo
diff --git a/go.sum b/go.sum
index 815b694..6cb589e 100644
--- a/go.sum
+++ b/go.sum
@@ -8,6 +8,8 @@ amadan.net/rastrillo/native/server v0.0.0-20260923173546-2a5d07b2c8d3 h1:5EFx7BL
amadan.net/rastrillo/native/server v0.0.0-20260923173546-2a5d07b2c8d3/go.mod h1:ZaaxeE278dJltdrLwmwpxUjQ5wuKzqDAVSNRet+WupY=
amadan.net/rastrillo/rastrillo v0.26.1-0.20260908075707-29e4491631bd h1:jlFSt95M1ontOg+VePU+kIJpChtWqDQAbnmlxqCnbgc=
amadan.net/rastrillo/rastrillo v0.26.1-0.20260908075707-29e4491631bd/go.mod h1:RpyHVPD0udcSfHJroY0KZE/FUjgw6Tvfo8SJm2qeZGE=
+github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
+github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/carlosframework/rastrillo v0.23.0 h1:tKAAlwPt4Pg/rkqk7o6jvV12bbZ0r34oEVpuOlKfX7w=
github.com/carlosframework/rastrillo v0.23.0/go.mod h1:pZlrE5F5OhspvZFzef0DrfjHAjA8FXycb9J5/8vc8Tw=
github.com/chromedp/cdproto v0.0.0-20250724212937-08a3db8b4327 h1:UQ4AU+BGti3Sy/aLU8KVseYKNALcX9UXY6DfpwQ6J8E=
diff --git a/internal/guardstest/forbidden_imports_test.go b/internal/guardstest/forbidden_imports_test.go
index ebb6af6..b0b8d80 100644
--- a/internal/guardstest/forbidden_imports_test.go
+++ b/internal/guardstest/forbidden_imports_test.go
@@ -27,3 +27,31 @@ func TestNoCgoSQLiteDriver(t *testing.T) {
}
}
}
+
+// preMoveRastrillo is rastrillo's module path before it moved to
+// amadan.net/rastrillo/rastrillo (v0.25.0). Nothing after v0.23.0 was
+// released under it, so code importing it gets no rastrillo fix — which
+// is how Sheets kept zooming iOS on every tap for a month after rastrillo
+// fixed it (polish audit r3, item 1).
+const preMoveRastrillo = "github.com/carlosframework/rastrillo"
+
+// preMoveAllowed is the one file that may still import it, and why:
+// rastrillo/native's server takes the old path's *sessions.Sessions.
+// Delete the entry when native/server moves.
+var preMoveAllowed = map[string]string{
+ "internal/sheets/native.go": preMoveRastrillo + "/sessions",
+}
+
+// TestNoPreMoveRastrillo fails on any import of rastrillo's old module
+// path outside preMoveAllowed.
+func TestNoPreMoveRastrillo(t *testing.T) {
+ root := repoRoot(t)
+ for _, path := range goFiles(t, root) {
+ rel := relPath(t, root, path)
+ for _, imp := range fileImports(t, path) {
+ if importUnder(imp, preMoveRastrillo) && preMoveAllowed[rel] != imp {
+ t.Errorf("%s: imports %q, rastrillo's frozen pre-move path; use amadan.net/rastrillo/rastrillo", rel, imp)
+ }
+ }
+ }
+}
diff --git a/internal/guardstest/userid_test.go b/internal/guardstest/userid_test.go
index b00c7ba..993ac78 100644
--- a/internal/guardstest/userid_test.go
+++ b/internal/guardstest/userid_test.go
@@ -33,7 +33,7 @@ import (
// it covers the violation it was meant to catch. Docs hit exactly that
// (four warning comments, no call sites) and made the same change.
const (
- sessionsPkg = "github.com/carlosframework/rastrillo/sessions"
+ sessionsPkg = "amadan.net/rastrillo/rastrillo/sessions"
forbiddenIdent = "UserID"
)
diff --git a/internal/sheets/app.go b/internal/sheets/app.go
index 01f106d..0dc93c3 100644
--- a/internal/sheets/app.go
+++ b/internal/sheets/app.go
@@ -8,11 +8,11 @@ import (
"amadan.net/oficina/estilo.git/chrome"
"amadan.net/oficina/home/connect"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/sessions"
- "github.com/carlosframework/rastrillo/auth"
- "github.com/carlosframework/rastrillo/csrf"
- "github.com/carlosframework/rastrillo/jobs"
+ "amadan.net/rastrillo/rastrillo/auth"
+ "amadan.net/rastrillo/rastrillo/csrf"
+ "amadan.net/rastrillo/rastrillo/jobs"
"github.com/go-chi/chi/v5"
"gorm.io/gorm"
diff --git a/internal/sheets/auth.go b/internal/sheets/auth.go
index 3a28d68..cb9f668 100644
--- a/internal/sheets/auth.go
+++ b/internal/sheets/auth.go
@@ -10,8 +10,8 @@ import (
"os"
"strings"
- "github.com/carlosframework/rastrillo/auth"
- "github.com/carlosframework/rastrillo/mail"
+ "amadan.net/rastrillo/rastrillo/auth"
+ "amadan.net/rastrillo/rastrillo/mail"
)
// AuthEnv is everything sign-in needs from the environment, already
diff --git a/internal/sheets/begin_test.go b/internal/sheets/begin_test.go
index 71aacab..f5c4bad 100644
--- a/internal/sheets/begin_test.go
+++ b/internal/sheets/begin_test.go
@@ -10,8 +10,8 @@ import (
"sync"
"testing"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
"amadan.net/oficina/sheets/internal/sheets/seal"
)
diff --git a/internal/sheets/errors.go b/internal/sheets/errors.go
index de31d96..a900dd3 100644
--- a/internal/sheets/errors.go
+++ b/internal/sheets/errors.go
@@ -27,7 +27,7 @@ import (
"strings"
"amadan.net/oficina/estilo.git/chrome"
- "github.com/carlosframework/rastrillo"
+ "amadan.net/rastrillo/rastrillo"
"github.com/go-chi/chi/v5"
)
diff --git a/internal/sheets/handlers_import.go b/internal/sheets/handlers_import.go
index cf36210..a8e973e 100644
--- a/internal/sheets/handlers_import.go
+++ b/internal/sheets/handlers_import.go
@@ -7,8 +7,8 @@ import (
"net/http"
"strconv"
- "github.com/carlosframework/rastrillo/jobs"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/jobs"
+ "amadan.net/rastrillo/rastrillo/sessions"
"amadan.net/oficina/sheets/internal/sheets/xlsx"
)
diff --git a/internal/sheets/helpers_test.go b/internal/sheets/helpers_test.go
index 4f4e797..9821d68 100644
--- a/internal/sheets/helpers_test.go
+++ b/internal/sheets/helpers_test.go
@@ -9,8 +9,8 @@ import (
"sync"
"testing"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
"amadan.net/oficina/sheets/internal/sheets/seal"
)
diff --git a/internal/sheets/home.go b/internal/sheets/home.go
index 32cea90..a1261f2 100644
--- a/internal/sheets/home.go
+++ b/internal/sheets/home.go
@@ -14,8 +14,8 @@ import (
"amadan.net/oficina/home/connect"
"amadan.net/oficina/home/connect/linkstore"
- "github.com/carlosframework/rastrillo/csrf"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/csrf"
+ "amadan.net/rastrillo/rastrillo/sessions"
)
var errHome = errors.New("sheets: Home connection unavailable")
diff --git a/internal/sheets/home_navigation_test.go b/internal/sheets/home_navigation_test.go
index 9f36663..f78233c 100644
--- a/internal/sheets/home_navigation_test.go
+++ b/internal/sheets/home_navigation_test.go
@@ -2,8 +2,8 @@ package sheets
import (
"amadan.net/oficina/home/connect"
+ "amadan.net/rastrillo/rastrillo"
"context"
- "github.com/carlosframework/rastrillo"
"net/http"
"net/http/httptest"
"net/url"
diff --git a/internal/sheets/home_test.go b/internal/sheets/home_test.go
index 8526e34..aa3dff7 100644
--- a/internal/sheets/home_test.go
+++ b/internal/sheets/home_test.go
@@ -14,7 +14,7 @@ import (
"amadan.net/oficina/home/connect"
"amadan.net/rastrillo/rastrillo/assertion"
assertioncrypto "amadan.net/rastrillo/rastrillo/crypto"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/sessions"
)
const homeTestIssuer = "https://id.example.com"
diff --git a/internal/sheets/jobpages.go b/internal/sheets/jobpages.go
index 9fb3ea0..713f84e 100644
--- a/internal/sheets/jobpages.go
+++ b/internal/sheets/jobpages.go
@@ -4,7 +4,7 @@ import (
"bytes"
"net/http"
- "github.com/carlosframework/rastrillo/jobs"
+ "amadan.net/rastrillo/rastrillo/jobs"
)
// jobPageView is the job status page's payload.
diff --git a/internal/sheets/migrations.go b/internal/sheets/migrations.go
index da34efc..d66f731 100644
--- a/internal/sheets/migrations.go
+++ b/internal/sheets/migrations.go
@@ -5,9 +5,9 @@ import (
"amadan.net/oficina/home/handoff"
"embed"
- "github.com/carlosframework/rastrillo/auth"
- "github.com/carlosframework/rastrillo/migrate"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/auth"
+ "amadan.net/rastrillo/rastrillo/migrate"
+ "amadan.net/rastrillo/rastrillo/sessions"
"amadan.net/oficina/sheets/internal/sheets/store"
)
diff --git a/internal/sheets/native.go b/internal/sheets/native.go
index b903d81..d6a271a 100644
--- a/internal/sheets/native.go
+++ b/internal/sheets/native.go
@@ -6,7 +6,15 @@ import (
"strings"
nativeauth "amadan.net/rastrillo/native/server"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/sessions"
+
+ // The one import left on rastrillo's pre-move path, on purpose:
+ // rastrillo/native's server (2a5d07b, and its main) still takes a
+ // github.com/carlosframework/rastrillo *sessions.Sessions. Both
+ // sessions packages read and write the same frozen sessions table, so
+ // a session native sign-in mints is an ordinary session to the app. Move this to
+ // amadan.net/rastrillo/rastrillo/sessions when native/server moves.
+ presessions "github.com/carlosframework/rastrillo/sessions"
"github.com/go-chi/chi/v5"
)
@@ -16,7 +24,7 @@ func (a *App) ConfigureNative() error {
if err != nil {
return err
}
- s, err := sessions.New(sessions.Config{DB: d, Origin: a.origin, SigninPath: "/signin"})
+ s, err := presessions.New(presessions.Config{DB: d, Origin: a.origin, SigninPath: "/signin"})
if err != nil {
return err
}
diff --git a/internal/sheets/render.go b/internal/sheets/render.go
index 9470a6e..e7de2f8 100644
--- a/internal/sheets/render.go
+++ b/internal/sheets/render.go
@@ -18,8 +18,8 @@ import (
estilomenu "amadan.net/oficina/estilo.git/menu"
"amadan.net/oficina/estilo.git/theme"
- "github.com/carlosframework/rastrillo"
- "github.com/carlosframework/rastrillo/ui"
+ "amadan.net/rastrillo/rastrillo"
+ "amadan.net/rastrillo/rastrillo/ui"
)
// templatesFS holds this app's own pages. rastrillo's partials come
diff --git a/internal/sheets/signin.go b/internal/sheets/signin.go
index c59e14a..9759ccb 100644
--- a/internal/sheets/signin.go
+++ b/internal/sheets/signin.go
@@ -7,7 +7,7 @@ import (
"amadan.net/oficina/estilo.git/brand"
"amadan.net/oficina/estilo.git/chrome"
"amadan.net/oficina/estilo.git/sky"
- "github.com/carlosframework/rastrillo/sessions"
+ "amadan.net/rastrillo/rastrillo/sessions"
)
// The sign-in pages are estilo's (estilo-signin, estilo-signin-sent,
diff --git a/internal/sheets/signin_test.go b/internal/sheets/signin_test.go
index 5daf4a8..77a0993 100644
--- a/internal/sheets/signin_test.go
+++ b/internal/sheets/signin_test.go
@@ -8,8 +8,8 @@ import (
"strings"
"testing"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
)
// TestSigninErrorNeverFallsThroughSilently is the reason signinError
diff --git a/internal/sheets/static/tokens.css b/internal/sheets/static/tokens.css
index 16a8809..10f6da5 100644
--- a/internal/sheets/static/tokens.css
+++ b/internal/sheets/static/tokens.css
@@ -62,8 +62,10 @@
Padding values are load-bearing for SC 2.5.8 Target Size (AA, new in
WCAG 2.2): pagination chips measure about 30px, row action pills
- about 27px and buttons about 34px on their smaller axis, all clear of
- the 24px minimum. Do not shrink them without re-measuring.
+ about 27px, and the button sizes about 28px (sm), 34px (default) and
+ 44px (lg) on their smaller axis, all clear of the 24px minimum. Do
+ not shrink them without re-measuring; the button block shows the
+ arithmetic.
Type sizes are rem, not px, so the whole scale tracks a reader who has
raised their browser's default font size. Spacing is rem for the same
@@ -73,6 +75,7 @@
/* ── Scale: type and spacing. Theme-independent. Radius is not here —
it is part of the theme's shape axis; see themes/. ────────────── */
:root {
+ --rst-fs-lg: 1.0625rem; /* 17px — the one step above base */
--rst-fs-base: 0.875rem; /* 14px at the browser default */
--rst-fs-sm: 0.78125rem; /* 12.5px */
--rst-fs-xs: 0.71875rem; /* 11.5px */
@@ -244,6 +247,56 @@ body {
filter: brightness(0.9);
}
+/* ── Button sizes ─────────────────────────────────────────────────────
+ Three steps, and they are a size scale rather than a set of variants:
+ size composes with primary/ghost/danger, so `rst-btn="primary lg"` is
+ the ordinary spelling of a form's submit.
+
+ The default step is the one the page-header action and the row pill
+ want — small, dense, a control beside other controls. It was the ONLY
+ step for a long time, and that is how a form's submit ended up
+ wearing it: a 34px, 12.5px-labelled button stretched across a 44rem
+ column, which reads as a skinny bar rather than the thing the whole
+ screen is asking you to press. A CTA is not a toolbar button; give it
+ `lg`.
+
+ Measured on the smaller axis, against SC 2.5.8's 24px floor — padding
+ both sides, plus the label's line box, plus the 1px border top and
+ bottom (the border is why the default step is 34px and not 32px). The
+ header comment carries these too; keep the two in step:
+ sm 0.3rem × 2 + 11.5px × 1.4 + 2 = 9.6 + 16.1 + 2 ≈ 28px
+ default 0.45rem × 2 + 12.5px × 1.4 + 2 = 14.4 + 17.5 + 2 ≈ 34px
+ lg 0.7rem × 2 + 14px × 1.4 + 2 = 22.4 + 19.6 + 2 ≈ 44px
+ sm is the tightest thing in the file that is still a button. It is
+ for a dense row of them, not for making an ordinary button smaller,
+ and there is deliberately nothing below it. */
+.rst-btn--sm, [rst-btn~="sm"] {
+ font-size: var(--rst-fs-xs);
+ padding: 0.3rem 0.55rem;
+}
+.rst-btn--lg, [rst-btn~="lg"] {
+ font-size: var(--rst-fs-base);
+ padding: 0.7rem 1.15rem;
+}
+
+/* block — a button that fills its container, for the one-action form
+ (sign in, sign up, a confirm page) where the submit IS the screen.
+ It centres its own label: .rst-btn sets no justify-content, so a
+ stretched button's text sits at the row's flex-start and reads as a
+ mistake rather than a choice.
+
+ Pair it with lg. A block button at the default size is precisely the
+ skinny bar described above — the width comes from the container and
+ the height does not follow, so the ratio goes wrong in proportion to
+ how wide the column is. Nothing here enforces that pairing, because a
+ narrow container is a legitimate place for a block button at the
+ default size; the wide ones are where it fails. */
+.rst-btn--block, [rst-btn~="block"] {
+ display: flex;
+ justify-content: center;
+ width: 100%;
+}
+
/* busy — the loading state rastrillo.js gives every submit button on
its way out, and the one state of a button that is not a variant:
any .rst-btn can wear it. The spinner is a real child element
@@ -656,7 +709,7 @@ body {
document outline, not a paragraph dressed up as one. */
.rst-empty__title, [rst-empty-title] {
color: var(--rst-text);
- font-size: 1.0625rem;
+ font-size: var(--rst-fs-lg);
font-weight: 600;
margin: 0 0 var(--rst-sp-2);
}
@@ -733,12 +786,132 @@ body {
.rst-badge--negative, [rst-badge~="negative"] { background: var(--rst-tone-negative-bg); border-color: var(--rst-tone-negative-fg); color: var(--rst-tone-negative-fg); }
.rst-badge--neutral, [rst-badge~="neutral"] { background: var(--rst-tone-neutral-bg); border-color: var(--rst-tone-neutral-fg); color: var(--rst-tone-neutral-fg); }
-/* meter — 4px capacity bar; the number rides beside it as text. */
+/* meter — 4px capacity bar; the number rides beside it as text.
+
+ The bar is a native <meter> (spec §6-v2.4), and styling one is the
+ one place in this file where the same declaration has to be written
+ three times: once on the element, once for the WebKit/Blink
+ pseudo-elements, once for the Firefox one. They cannot share a rule.
+ A selector list containing a pseudo-element an engine does not know
+ is invalid AS A WHOLE in that engine, so ::-webkit-meter-bar and
+ ::-moz-meter-bar in one comma-separated rule would style nothing
+ anywhere. That is why the repetition below is not tidied up.
+
+ The two engines also disagree about which pseudo-element is which.
+ In WebKit/Blink ::-webkit-meter-bar is the TRACK and
+ ::-webkit-meter-optimum-value is the FILL; in Firefox the element
+ itself is the track and ::-moz-meter-bar is the FILL. Read the three
+ blocks with that in mind or they look contradictory.
+
+ HONESTLY FLAGGED: the -moz- rule is unverified. This project's
+ browser drive is Chromium, so the WebKit/Blink path below is measured
+ and the Firefox path is written from the spec and reasoned about. It
+ was shipped that way knowingly (Paul's call). If a Firefox drive ever
+ lands, this is the first rule to point it at.
+
+ The old markup was a <span> with an <i> in it sized by
+ --rst-meter-fill. That custom property is gone; an app that set it is
+ setting nothing now, which is why it is called out in the changelog
+ rather than only here. */
.rst-meter, [rst-meter] { align-items: center; color: var(--rst-text-muted); display: inline-flex; font-size: var(--rst-fs-xs); gap: var(--rst-sp-2); }
-.rst-meter__bar, [rst-meter-bar] { background: var(--rst-accent-soft); border-radius: 2px; flex: 1; height: 4px; min-width: 34px; overflow: hidden; }
-.rst-meter__bar i, [rst-meter-bar] i { background: var(--rst-accent); border-radius: 2px; display: block; height: 100%; width: var(--rst-meter-fill, 0%); }
+.rst-meter__bar, [rst-meter-bar] { appearance: none; background: var(--rst-accent-soft); block-size: 4px; border: 0; border-radius: 2px; flex: 1; min-inline-size: 34px; }
+.rst-meter__bar::-webkit-meter-inner-element, [rst-meter-bar]::-webkit-meter-inner-element { block-size: 100%; }
+.rst-meter__bar::-webkit-meter-bar, [rst-meter-bar]::-webkit-meter-bar { background: var(--rst-accent-soft); block-size: 100%; border: 0; border-radius: 2px; }
+.rst-meter__bar::-webkit-meter-optimum-value, [rst-meter-bar]::-webkit-meter-optimum-value { background: var(--rst-accent); border-radius: 2px; }
+.rst-meter__bar::-moz-meter-bar, [rst-meter-bar]::-moz-meter-bar { background: var(--rst-accent); border-radius: 2px; }
.rst-meter__num, [rst-meter-num] { font-variant-numeric: tabular-nums; white-space: nowrap; }
+/* stats — the instrument strip a dashboard or a report opens with: a
+ lead reading at headline size, companion readings beside it, divided
+ by hairlines inside one card.
+
+ One band, one cell, one lead variant. The headline stat and the
+ counts next to it are the same component at two sizes (spec
+ §6-v2.4), so there is no second kind to keep in step with this one.
+
+ flex-wrap and a flex-basis rather than a grid with a column count.
+ Any number of cells has to work — three on one dashboard, five on
+ the next — and a grid would need the caller to say how many. The
+ basis is what decides when the strip becomes two rows, and the lead
+ cell's is larger so it keeps the line to itself when the others
+ wrap under it.
+
+ The hairline is border-inline-start on every cell but the first,
+ which is what makes the strip read as ONE instrument rather than as
+ a row of cards. Logical, so it lands on the right in Arabic. A
+ wrapped cell keeps its line, and that is the one visual compromise
+ here: at two rows the first cell of the second row draws a leading
+ hairline against the card's edge. It is a hairline, and the
+ alternative — :nth-child arithmetic against a column count nobody
+ declared — is the grid this deliberately is not. */
+.rst-stats, [rst-stats] {
+ background: var(--rst-surface);
+ border: 1px solid var(--rst-line);
+ border-radius: var(--rst-radius);
+ display: flex;
+ flex-wrap: wrap;
+}
+.rst-stat, [rst-stat] {
+ border-inline-start: 1px solid var(--rst-line);
+ display: flex;
+ flex: 1 1 9rem;
+ flex-direction: column;
+ gap: 0.15rem;
+ min-inline-size: 0;
+ padding: var(--rst-sp-4);
+}
+.rst-stat:first-child, [rst-stat]:first-child {
+ border-inline-start: 0;
+}
+.rst-stat--lead, [rst-stat~="lead"] {
+ flex-basis: 14rem;
+}
+/* The eyebrow. Uppercase and tracked, the same grammar every label in
+ this system uses above a value, so a band of cells reads as one row
+ of labels rather than as four headings. */
+.rst-stat__label, [rst-stat-label] {
+ color: var(--rst-text-muted);
+ font-size: var(--rst-fs-xs);
+ font-weight: 650;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+}
+/* tabular-nums so a column of readings lines up on its digits, and so
+ a number that changes on a poll does not jitter its neighbours. */
+.rst-stat__num, [rst-stat-num] {
+ font-size: 1.5rem;
+ font-variant-numeric: tabular-nums;
+ font-weight: 650;
+ line-height: 1.1;
+}
+.rst-stat--lead .rst-stat__num, [rst-stat~="lead"] [rst-stat-num] {
+ font-size: 2.1rem;
+}
+/* The delta is TEXT in a colour, not a colour. Its sign is written by
+ the caller and is the signal a reader who cannot tell the two hues
+ apart is reading; the colour is the second one (WCAG 2.2 AA 1.4.1).
+ Both hues are held at 4.5:1 against this card by the contrast gate
+ in the same commit that added them — they are text, so the floor
+ applies whether or not the colour carries meaning of its own. */
+.rst-stat__delta, [rst-stat-delta] {
+ font-size: var(--rst-fs-sm);
+ font-variant-numeric: tabular-nums;
+ font-weight: 600;
+}
+.rst-stat__delta[data-tone="positive"], [rst-stat-delta][rst-tone~="positive"] {
+ color: var(--rst-tone-positive-fg);
+}
+.rst-stat__delta[data-tone="negative"], [rst-stat-delta][rst-tone~="negative"] {
+ color: var(--rst-tone-negative-fg);
+}
+.rst-stat__delta[data-tone="neutral"], [rst-stat-delta][rst-tone~="neutral"] {
+ color: var(--rst-text-muted);
+}
+.rst-stat__note, [rst-stat-note] {
+ color: var(--rst-text-faint);
+ font-size: var(--rst-fs-xs);
+}
+
/* person — avatar + name + email; avatar is decoration, text is identity. */
.rst-person, [rst-person] { align-items: center; color: inherit; display: inline-flex; gap: 0.7rem; min-width: 0; text-decoration: none; }
.rst-person__av, [rst-person-av] { align-items: center; background: var(--rst-accent); border-radius: 50%; color: var(--rst-on-accent); display: flex; flex: none; font-size: 0.6875rem; font-weight: 600; height: 28px; justify-content: center; width: 28px; }
@@ -1039,6 +1212,17 @@ details[open] > summary > .rst-caret, details[open] > summary > [rst-caret] { tr
and it is wide enough for the postcodes and codes it is for. The
max keeps it from overflowing a column narrower than itself. */
.rst-input--short, [rst-input~="short"] { inline-size: 8rem; max-inline-size: 100%; }
+/* primary is the form's headline field — the title or name the record is
+ known by — and the size is the whole signal, because the label above it
+ stays the same quiet line every other field gets. font-size has to be
+ restated rather than inherited: .rst-input sets `font: inherit`, so the
+ shorthand would otherwise reset it back to the body's 14px. 550 is the
+ weight .rst-nm and .rst-person__name already give a name; 600 reads as a
+ heading, which this is not. The padding grows with the type so the box
+ keeps its proportions instead of looking like a squeezed plain input.
+ 17px is also where iOS Safari stops zooming a focused input, which the
+ 14px base does not clear — a real bonus, not the reason. */
+.rst-input--primary, [rst-input~="primary"] { font-size: var(--rst-fs-lg); font-weight: 550; padding: 0.6rem 0.7rem; }
textarea.rst-input, textarea[rst-input] { min-height: 5rem; resize: vertical; }
/* field-text/field-textarea (the interim pair the manifest generator
emits) mark a required label with * and put the textarea on its own
@@ -1288,6 +1472,19 @@ dialog.rst-modal-panel, dialog[rst-modal-panel] { block-size: auto; color: inher
animation: rst-spin 0.8s linear infinite;
}
@keyframes rst-spin { to { transform: rotate(1turn); } }
+
+/* A running job's determinate bar: a native <progress>, styled the same
+ way and for the same reasons as [rst-meter-bar] — see that block for
+ why the three engines need three rules that cannot be merged, and for
+ the same honest flag about the -moz- one being unverified here.
+ <progress>'s pseudo-elements are its own: ::-webkit-progress-bar is
+ the track, ::-webkit-progress-value the fill, ::-moz-progress-bar the
+ fill. It is a block on its own line under the sentence, because it
+ measures the job the sentence is about. */
+.rst-job__bar, [rst-job-bar] { appearance: none; background: var(--rst-accent-soft); block-size: 4px; border: 0; border-radius: 2px; display: block; inline-size: 100%; margin-block-start: var(--rst-sp-2); }
+.rst-job__bar::-webkit-progress-bar, [rst-job-bar]::-webkit-progress-bar { background: var(--rst-accent-soft); border-radius: 2px; }
+.rst-job__bar::-webkit-progress-value, [rst-job-bar]::-webkit-progress-value { background: var(--rst-accent); border-radius: 2px; }
+.rst-job__bar::-moz-progress-bar, [rst-job-bar]::-moz-progress-bar { background: var(--rst-accent); border-radius: 2px; }
@media (prefers-reduced-motion: reduce) {
.rst-spin, [rst-spin] { animation: none; opacity: 0.5; }
}
@@ -1343,6 +1540,72 @@ dialog.rst-modal-panel, dialog[rst-modal-panel] { block-size: auto; color: inher
.rst-dtp__set, [rst-dtp-set] { flex: none; font-size: var(--rst-fs-xs); color: var(--rst-muted); }
.rst-dtp__hint, [rst-dtp-hint] { color: var(--rst-muted); font-size: var(--rst-fs-xs); padding: 0.35rem 0.65rem 0.15rem; }
+/* The popup opens above the field where there is no room below it —
+ datetime.js measures and sets .is-above, because a panel hanging off
+ the bottom of the window is a panel whose last week nobody can click.
+ One rule for both popups: only ever one of them is open. */
+.rst-dtp.is-above .rst-dtp__list, [rst-dtp].is-above [rst-dtp-list], .rst-dtp.is-above .rst-cal, [rst-dtp].is-above [rst-cal] { inset-block-end: 100%; margin-block-end: 4px; margin-block-start: 0; top: auto; }
+/* A completion offered rather than chosen — the other months a
+ half-typed word could still have meant. Lighter than the reading
+ above it, because it is a second-best by construction. */
+.rst-dtp__row--alt .rst-dtp__label, [rst-dtp-row~="alt"] [rst-dtp-label] { color: var(--rst-text-muted); }
+
+/* ── The calendar overlay (ui/calendar.js): the month grid a date
+ field's button opens. A real <table> with real column headers,
+ because that is what a calendar is, with role="grid" over the top
+ and a roving tabindex so exactly one day sits in the tab order.
+
+ Sized in rem so the grid keeps its shape when a page is zoomed:
+ seven columns of text, not seven columns of pixels. A fixed inline
+ size rather than the field's, because a calendar is a calendar
+ whatever it hangs under — a month stretched across a wide input is
+ a grid nobody can aim at.
+
+ Everything here is logical (inline/block, never left/right), so a
+ right-to-left page mirrors the panel and the grid together. The
+ chevrons are the one thing that needs saying twice, below.
+ ───────────────────────────────────────────────────────────────── */
+.rst-cal, [rst-cal] { background: var(--rst-surface); border: 1px solid var(--rst-line); border-radius: 9px; box-shadow: var(--rst-shadow-pop); inline-size: 18rem; inset-inline-start: 0; margin-block-start: 4px; padding: var(--rst-sp-2); position: absolute; top: 100%; z-index: 40; }
+.rst-cal__head, [rst-cal-head] { align-items: center; display: flex; gap: var(--rst-sp-1); justify-content: space-between; padding-block-end: var(--rst-sp-2); }
+.rst-cal__title, [rst-cal-title] { flex: 1; font-size: var(--rst-fs-sm); font-weight: 600; text-align: center; }
+.rst-cal__nav, [rst-cal-nav] { align-items: center; background: none; block-size: 1.75rem; border: 0; border-radius: var(--rst-radius-sm); color: var(--rst-muted); cursor: pointer; display: flex; inline-size: 1.75rem; justify-content: center; padding: 0; }
+.rst-cal__nav:hover:not(:disabled), [rst-cal-nav]:hover:not(:disabled) { background: var(--rst-accent-soft); color: var(--rst-text); }
+/* A month with nothing pickable in it — past the field's min, or past
+ its max. Dimmed and inert rather than removed, so the header keeps
+ its shape and the title stays where the eye left it. */
+.rst-cal__nav:disabled, [rst-cal-nav]:disabled { cursor: default; opacity: 0.35; }
+.rst-cal__nav svg, [rst-cal-nav] svg { block-size: 1.1rem; inline-size: 1.1rem; }
+/* One chevron, drawn once and turned round for the other direction, so
+ "back" always points at the start of the line — which is the other
+ end of the box in a right-to-left page, and handled there by the
+ panel's own direction rather than a second rule. */
+[rst-cal-nav~="next"] svg, .rst-cal__nav--next svg { transform: scaleX(-1); }
+.rst-cal__grid, [rst-cal-grid] { border-collapse: collapse; inline-size: 100%; table-layout: fixed; }
+.rst-cal__grid th, [rst-cal-grid] th { color: var(--rst-muted); font-size: var(--rst-fs-xs); font-weight: 500; padding-block: var(--rst-sp-1); text-align: center; }
+.rst-cal__day, [rst-cal-day] { border-radius: var(--rst-radius-sm); cursor: pointer; font-size: var(--rst-fs-sm); font-variant-numeric: tabular-nums; line-height: 2.15; text-align: center; }
+.rst-cal__day:hover, [rst-cal-day]:hover { background: var(--rst-accent-soft); }
+/* The days either side of the month. Still pickable — reaching for the
+ 1st from the row above it is how people use a calendar — but plainly
+ not part of the month on screen. */
+.rst-cal__day.is-outside, [rst-cal-day].is-outside { color: var(--rst-text-faint); }
+/* Today is a ring rather than a fill, so it can still be read when the
+ selection is sitting on top of it. */
+.rst-cal__day.is-today, [rst-cal-day].is-today { box-shadow: inset 0 0 0 1px var(--rst-line-strong); font-weight: 600; }
+/* What the text in the box currently reads as: an outline that follows
+ the words as they are typed. Deliberately quieter than the selection
+ — it is a preview, and nothing has been chosen yet. */
+.rst-cal__day.is-preview, [rst-cal-day].is-preview { box-shadow: inset 0 0 0 2px var(--rst-accent); }
+/* The committed value. aria-selected says so in the accessibility tree;
+ this is the matching visual, never the only signal. */
+.rst-cal__day.is-selected, [rst-cal-day].is-selected { background: var(--rst-accent); color: var(--rst-on-accent); font-weight: 600; }
+.rst-cal__day.is-selected.is-outside, [rst-cal-day].is-selected.is-outside { color: var(--rst-on-accent); }
+/* Outside the field's own min/max. aria-disabled carries it to a screen
+ reader and calendar.js refuses the pick; this says the same to the
+ eye. */
+.rst-cal__day.is-disabled, [rst-cal-day].is-disabled { color: var(--rst-text-faint); cursor: default; text-decoration: line-through; }
+.rst-cal__day.is-disabled:hover, [rst-cal-day].is-disabled:hover { background: none; }
+.rst-cal__day:focus-visible, [rst-cal-day]:focus-visible { outline: 2px solid var(--rst-accent); outline-offset: -2px; }
+
/* ── Shells: the page frames an app's layout template wraps .rst-page
in — topbar and sidebar. Written in logical properties throughout,
so a right-to-left locale gets a mirrored shell for free: the rail
@@ -1618,6 +1881,40 @@ dialog.rst-modal-panel, dialog[rst-modal-panel] { block-size: auto; color: inher
.rst-error__cta, [rst-error-cta] { display: flex; flex-wrap: wrap; gap: var(--rst-sp-2); justify-content: center; margin-block: var(--rst-sp-5) 0; }
.rst-error__ref, [rst-error-ref] { color: var(--rst-text-faint); margin-block: 2rem 0; }
+/* ---------------------------------------------------------------------
+ Touch: the two zooms nobody asked for.
+
+ Mobile Safari zooms the whole page when it focuses a form control
+ whose text is under 16px, and this file's base type is 14px on
+ purpose. So every text-entry control comes back up to 16px where the
+ pointer is coarse, and stays 14px under a mouse. max() rather than a
+ flat 1rem, so a control deliberately set larger keeps its size; rem
+ rather than px, so a reader who raised the browser default keeps the
+ increase. This is the fix. The other one — user-scalable=no in the
+ viewport tag — buys the same quiet by taking pinch-zoom away from
+ everyone, which is a WCAG 1.4.4 failure and not on offer here.
+
+ Double-tap is the second zoom: tap a button or a row twice in quick
+ succession and the second tap lands as a zoom gesture rather than a
+ click. touch-action: manipulation drops that gesture on interactive
+ elements only, so panning and pinch-zoom are untouched, and so is
+ double-tapping prose or an image, which is a real way to read a
+ narrow column. :where() weighs nothing, so any rule can override it.
+ --------------------------------------------------------------------- */
+
+@media (pointer: coarse) {
+ input, select, textarea,
+ .rst-input, [rst-input],
+ .rst-textarea, [rst-textarea],
+ .rst-search input[type="search"], [rst-search] input[type="search"] {
+ font-size: max(1rem, 1em);
+ }
+}
+
+:where(a[href], button, input, select, textarea, label, summary, [role="button"], [role="tab"], [role="option"]) {
+ touch-action: manipulation;
+}
+
/* ---------------------------------------------------------------------
Utilities, last on purpose.
diff --git a/internal/sheets/store/handle_blank_cap_test.go b/internal/sheets/store/handle_blank_cap_test.go
index f06ce08..fa46609 100644
--- a/internal/sheets/store/handle_blank_cap_test.go
+++ b/internal/sheets/store/handle_blank_cap_test.go
@@ -5,8 +5,8 @@ import (
"path/filepath"
"testing"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
"amadan.net/oficina/sheets/internal/sheets"
"amadan.net/oficina/sheets/internal/sheets/calc"
diff --git a/internal/sheets/store/handle_blank_crash_test.go b/internal/sheets/store/handle_blank_crash_test.go
index a52b072..a339e2c 100644
--- a/internal/sheets/store/handle_blank_crash_test.go
+++ b/internal/sheets/store/handle_blank_crash_test.go
@@ -6,8 +6,8 @@ import (
"path/filepath"
"testing"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
"amadan.net/oficina/sheets/internal/sheets"
"amadan.net/oficina/sheets/internal/sheets/calc"
diff --git a/internal/sheets/store/handle_blank_recovery_bench_test.go b/internal/sheets/store/handle_blank_recovery_bench_test.go
index 66e03f7..ff2c4a0 100644
--- a/internal/sheets/store/handle_blank_recovery_bench_test.go
+++ b/internal/sheets/store/handle_blank_recovery_bench_test.go
@@ -8,8 +8,8 @@ import (
"testing"
"time"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
"gorm.io/gorm"
"amadan.net/oficina/sheets/internal/sheets"
diff --git a/internal/sheets/store/handle_version_migration_test.go b/internal/sheets/store/handle_version_migration_test.go
index 9887a6e..f191a70 100644
--- a/internal/sheets/store/handle_version_migration_test.go
+++ b/internal/sheets/store/handle_version_migration_test.go
@@ -11,8 +11,8 @@ import (
"amadan.net/oficina/sheets/internal/sheets/calc"
"amadan.net/oficina/sheets/internal/sheets/seal"
"amadan.net/oficina/sheets/internal/sheets/store"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
)
func TestVersionWatermarkMigrationPreservesExistingContent(t *testing.T) {
diff --git a/internal/sheets/store/helpers_test.go b/internal/sheets/store/helpers_test.go
index 410d445..65e2208 100644
--- a/internal/sheets/store/helpers_test.go
+++ b/internal/sheets/store/helpers_test.go
@@ -4,8 +4,8 @@ import (
"context"
"testing"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
"gorm.io/gorm"
"amadan.net/oficina/sheets/internal/sheets"
diff --git a/internal/sheets/theme_assets_test.go b/internal/sheets/theme_assets_test.go
index c2bcfd4..b103d65 100644
--- a/internal/sheets/theme_assets_test.go
+++ b/internal/sheets/theme_assets_test.go
@@ -1,6 +1,7 @@
package sheets
import (
+ "io/fs"
"path"
"amadan.net/oficina/estilo.git/busy"
@@ -13,7 +14,7 @@ import (
"testing"
"amadan.net/oficina/estilo.git/theme"
- "github.com/carlosframework/rastrillo/ui"
+ "amadan.net/rastrillo/rastrillo/ui"
)
func TestSharedThemeAssetFingerprintAndCache(t *testing.T) {
@@ -95,4 +96,13 @@ func TestBusyRuleIsLinkedAndServed(t *testing.T) {
if i, j := strings.Index(page, "static/rastrillo."), strings.Index(page, "static/estilo/busy."); i < 0 || j < 0 {
t.Error("the shim or busy.js is missing")
}
+ // No rastrillo script on disk. `rastrillo doctor --fix` adds the ones
+ // the library ships and the app lacks, and the shim it adds at this
+ // pin is the old one, with the busy rule inside: loaded beside
+ // estilo's busy.js, the two rules fight. Delete what --fix adds.
+ for _, name := range []string{"static/rastrillo.js", "static/busy.js", "static/select.js", "static/datetime.js", "static/calendar.js"} {
+ if _, err := fs.Stat(staticFS, name); err == nil {
+ t.Errorf("%s is on disk; Sheets serves estilo's shim and busy.js, and no other rastrillo script", name)
+ }
+ }
}
diff --git a/internal/sheets/theme_test.go b/internal/sheets/theme_test.go
index 7772174..1af20df 100644
--- a/internal/sheets/theme_test.go
+++ b/internal/sheets/theme_test.go
@@ -16,7 +16,7 @@ import (
"testing"
"amadan.net/oficina/estilo.git/chrome"
- "github.com/carlosframework/rastrillo/ui"
+ "amadan.net/rastrillo/rastrillo/ui"
)
// The bug theme.go was written to stop coming back: data-theme takes the
diff --git a/internal/sheets/xlsx/blob.go b/internal/sheets/xlsx/blob.go
index 8871115..7911f77 100644
--- a/internal/sheets/xlsx/blob.go
+++ b/internal/sheets/xlsx/blob.go
@@ -5,7 +5,7 @@ import (
"context"
"fmt"
- "github.com/carlosframework/rastrillo/blobs"
+ "amadan.net/rastrillo/rastrillo/blobs"
"amadan.net/oficina/sheets/internal/sheets/store"
)
diff --git a/internal/sheets/xlsx/blob_test.go b/internal/sheets/xlsx/blob_test.go
index 2dfacab..5e59a43 100644
--- a/internal/sheets/xlsx/blob_test.go
+++ b/internal/sheets/xlsx/blob_test.go
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
- "github.com/carlosframework/rastrillo/blobs"
+ "amadan.net/rastrillo/rastrillo/blobs"
"amadan.net/oficina/sheets/internal/sheets/xlsx"
)
diff --git a/internal/sheets/xlsx/helpers_test.go b/internal/sheets/xlsx/helpers_test.go
index 0ebb55c..c3cc600 100644
--- a/internal/sheets/xlsx/helpers_test.go
+++ b/internal/sheets/xlsx/helpers_test.go
@@ -9,8 +9,8 @@ import (
"strconv"
"testing"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
"github.com/xuri/excelize/v2"
"gorm.io/gorm"
diff --git a/internal/sheets/xlsx/plaintext_test.go b/internal/sheets/xlsx/plaintext_test.go
index 33560bf..d670de2 100644
--- a/internal/sheets/xlsx/plaintext_test.go
+++ b/internal/sheets/xlsx/plaintext_test.go
@@ -6,8 +6,8 @@ import (
"path/filepath"
"testing"
- rdb "github.com/carlosframework/rastrillo/db"
- "github.com/carlosframework/rastrillo/migrate"
+ rdb "amadan.net/rastrillo/rastrillo/db"
+ "amadan.net/rastrillo/rastrillo/migrate"
"amadan.net/oficina/sheets/internal/sheets"
"amadan.net/oficina/sheets/internal/sheets/sealtest"
diff --git a/internal/sheets/zoom_browser_test.go b/internal/sheets/zoom_browser_test.go
index 749cd36..cdc1e3f 100644
--- a/internal/sheets/zoom_browser_test.go
+++ b/internal/sheets/zoom_browser_test.go
@@ -18,7 +18,7 @@ import (
"testing"
"time"
- "github.com/carlosframework/rastrillo/harness"
+ "amadan.net/rastrillo/rastrillo/harness"
"github.com/chromedp/cdproto/emulation"
"github.com/chromedp/cdproto/network"
"github.com/chromedp/chromedp"