Skip to content

Commit 602edb8

Browse files
committed
v1.10.25 — Sliding active-view bar, switch sounds, table polish + fixes
1 parent b1125d3 commit 602edb8

23 files changed

Lines changed: 1304 additions & 1038 deletions

‎CHANGELOG.md‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,26 @@ Versions follow [Semantic Versioning](https://semver.org/).
55

66
---
77

8+
## v1.10.25 — 2026-06-26
9+
10+
### Added
11+
12+
- **See whose inventory you're viewing at a glance.** A bright bar on the left edge slides to the avatar of the view you're currently in — your own, or a friend's — so you always know where you are.
13+
- **Little sounds when you switch.** A quick blip when you hop between your own accounts, and a softer, distinct one when you peek into a friend's inventory.
14+
15+
### Changed
16+
17+
- **Friendlier wording** across a few empty states and confirmations.
18+
- **Clearer inventory table.** The remaining-weight bar now sits under the value with room to breathe, grouped rows highlight properly on hover again, and the sort arrow is a cleaner chevron.
19+
20+
### Fixed
21+
22+
- **Clicking the friend you're already viewing now does nothing** — it used to bounce you back to your own inventory.
23+
- **Scanning a two-chip (twin) spool no longer opens its card twice.**
24+
- **Grouped rows now sort by their combined weight and capacity**, so the order matches what you see.
25+
26+
---
27+
828
## v1.10.24 — 2026-06-26
929

1030
### Added

‎CLAUDE.md‎

Lines changed: 7 additions & 328 deletions
Large diffs are not rendered by default.

‎WORKLOG.md‎

Lines changed: 14 additions & 39 deletions
Large diffs are not rendered by default.
90.6 KB
Loading

‎data/whatsnew.json‎

Lines changed: 628 additions & 523 deletions
Large diffs are not rendered by default.

‎docs/firestore-schema.md‎

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Firestore data structure (TigerTag)
2+
3+
> Extracted from `CLAUDE.md` to keep the always-loaded instructions lean. Read this on demand when touching Firestore reads/writes or the data model. Security rules live in the **backend repo** (`TigerTag_Firebase_Backend/firestore.rules`) — see CLAUDE.md → *Firestore Security Rules*.
4+
5+
```
6+
publicKeys/
7+
{key}/ — key = public code e.g. "4X7-K3M" (XXX-XXX format)
8+
uid string — owner uid
9+
claimedAt timestamp — when claimed
10+
11+
userProfiles/
12+
{uid}/ — public profile, readable by all authenticated users
13+
publicKey string — same as publicKeys entry (denormalised for display)
14+
displayName string — user's chosen pseudo
15+
isPublic boolean — whether inventory is publicly visible
16+
(color fields for avatar)
17+
18+
users/
19+
{uid}/
20+
displayName string — user's chosen pseudo
21+
googleName string — real name from Google Auth (admin reference only, never displayed)
22+
firstName string — first word of googleName
23+
lastName string — remainder of googleName
24+
email string
25+
roles string — "admin" | undefined
26+
Debug boolean — debug mode enabled
27+
publicKey string — discovery code XXX-XXX (also in publicKeys/{key})
28+
privateKey string — 40-char hex access token (used by Firestore rules)
29+
isPublic boolean — inventory publicly visible
30+
studioVersion string — last known app version (e.g. "1.8.0"), overwritten each session
31+
studioElectron string — Electron runtime version (e.g. "33.2.1")
32+
studioPlatform string — OS platform: "darwin" | "win32" | "linux"
33+
studioArch string — CPU arch: "arm64" | "x64"
34+
studioOsRelease string — kernel version (e.g. "23.5.0" = macOS Sonoma)
35+
studioOsVersion string — human-readable OS (e.g. "macOS 15.4", "Windows 11 Pro")
36+
studioLang string — app language setting (e.g. "fr")
37+
studioLocale string — system locale (e.g. "fr-FR")
38+
studioCountry string — country code derived from the locale region (e.g. "FR"); null when the locale has no region. Offline-derived, no IP geolocation
39+
studioTimezone string — IANA timezone (e.g. "Europe/Paris"), from Intl.DateTimeFormat
40+
studioLastSeen timestamp — server timestamp of last login (deployment targeting / churn)
41+
42+
telemetry/
43+
studio/ — aggregated lifetime metrics (standard Firebase pattern)
44+
sessionsCount number — total sessions (FieldValue.increment)
45+
versionsUsed string[]— all app versions ever used (FieldValue.arrayUnion)
46+
platformsUsed string[]— all platforms ever used (FieldValue.arrayUnion)
47+
langsUsed string[]— all app languages ever used (FieldValue.arrayUnion)
48+
countriesUsed string[]— all country codes ever seen (FieldValue.arrayUnion; only when derivable)
49+
lastSeen timestamp — server timestamp of last session
50+
td1sUsed boolean — true once a TD1s sensor was ever connected
51+
rfidReadersMax number — max simultaneous RFID readers ever seen (1 or 2)
52+
53+
inventory/
54+
{spoolId}/ — one document per spool
55+
uid string — RFID tag UID
56+
id_brand number
57+
id_material number
58+
color_name string
59+
online_color_list string[] — hex colors
60+
weight_available number — grams net
61+
container_weight number — grams
62+
container_id string — references data/container_spool/spools_filament.json
63+
capacity number — total spool capacity in grams
64+
last_update number — timestamp ms
65+
deleted boolean
66+
deleted_at number?
67+
twin_uid string? — linked RFID tag UID
68+
69+
friends/
70+
{friendUid}/
71+
displayName string
72+
addedAt timestamp
73+
key string — friend's privateKey at time of accept (used to verify access)
74+
75+
friendRequests/
76+
{requesterUid}/
77+
displayName string
78+
requestedAt timestamp
79+
key string — requester's privateKey (used for bidirectional accept)
80+
81+
blacklist/
82+
{blockedUid}/
83+
displayName string
84+
blockedAt timestamp
85+
86+
prefs/
87+
app/
88+
lang string — language code, synced across devices
89+
groupInv boolean — Studio inventory "group identical spools" toggle (Studio-only, synced across devices)
90+
autoManage boolean — Storage "Auto-organize" toggle (drives both auto-place + auto-free; per-account, synced across devices; localStorage `tigertag.autoManage.enabled` is the fast read cache). Migrated from the legacy split fields below (unified = either-was-on).
91+
autoStorage boolean — LEGACY (pre-merge) "Auto storage" toggle — read only for one-time migration into `autoManage`
92+
autoUnstorage boolean — LEGACY (pre-merge) "Auto unstorage" toggle — read only for one-time migration into `autoManage`
93+
```
94+
95+
## Connecting from a third-party app
96+
97+
```js
98+
// 1. Fetch config
99+
const config = await fetch("https://tigertag-cdn.web.app/__/firebase/init.json").then(r => r.json());
100+
firebase.initializeApp(config);
101+
102+
// 2. Sign in (user must have a TigerTag account)
103+
await firebase.auth().signInWithEmailAndPassword(email, password);
104+
// or: firebase.auth().signInWithPopup(new firebase.auth.GoogleAuthProvider())
105+
106+
// 3. Read inventory
107+
const uid = firebase.auth().currentUser.uid;
108+
const snap = await firebase.firestore()
109+
.collection("users").doc(uid)
110+
.collection("inventory")
111+
.get();
112+
snap.forEach(doc => console.log(doc.id, doc.data()));
113+
114+
// 4. Update spool weight
115+
await firebase.firestore()
116+
.collection("users").doc(uid)
117+
.collection("inventory").doc(spoolId)
118+
.update({ weight_available: 450, last_update: Date.now() });
119+
```

‎docs/i18n-keys.md‎

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# i18n keys — complete reference (TigerTag Studio)
2+
3+
> Extracted from `CLAUDE.md` to keep the always-loaded instructions lean. **Read this on demand instead of re-reading the locale JSON files.** All **9 locales** (en/fr/de/es/it/zh/pt/pt-pt/pl) have every key below. To add/change keys use `npm run i18n:add` (never hand-edit the locale files) — see CLAUDE.md → *i18n — workflow*.
4+
5+
### App / status
6+
| Key | Purpose |
7+
|-----|---------|
8+
| `appSubtitle` | Header subtitle |
9+
| `backendIdle` | Health tooltip idle |
10+
| `backendOk` | Health tooltip ok (also used with `— N ms` suffix) |
11+
| `backendErr` | Health tooltip error `{{n}}` |
12+
| `backendOffline` | Health tooltip offline |
13+
| `rfidConnected` | RFID label `{{name}}` |
14+
| `rfidNoReader` | RFID no reader |
15+
| `rfidScanned` | RFID scanned `{{uid}}` |
16+
| `rfidNotFound` | RFID unknown UID `{{uid}}` |
17+
| `welcomeBack` | Array of random greeting strings |
18+
19+
### Community / links
20+
| Key | Purpose |
21+
|-----|---------|
22+
| `githubBtn` | GitHub button |
23+
| `discordBtn` | Discord button |
24+
| `mobileApp` | QR label |
25+
| `mobileScan` | QR sub-label |
26+
27+
### Settings panel
28+
| Key | Purpose |
29+
|-----|---------|
30+
| `settingsOpenBtn` | Settings button label |
31+
| `settingsTitle` | Panel title |
32+
| `settingsAccount` | Account tab label |
33+
| `settingsData` | Data & Export tab label |
34+
| `settingsLang` | Language section label |
35+
| `settingsDebug` | Debug tab label |
36+
| `settingsSave` | Save & reload button |
37+
| `settingsApiLink` | Export URL field label |
38+
| `settingsExport` | Download JSON button |
39+
| `settingsCopied` | Copy confirmation |
40+
| `debugOpenBtn` | Open debug panel button |
41+
42+
### Account management
43+
| Key | Purpose |
44+
|-----|---------|
45+
| `addAccountLabel` | Add account button / modal title |
46+
| `addAccountSave` | Add & load (legacy, kept) |
47+
| `addAccountAuthError` | Friendly error for invalid email/API key |
48+
| `editAccountTitle` | Edit account modal title |
49+
| `btnSignIn` | Sign in button |
50+
| `btnEditAccount` | Edit account button |
51+
| `btnDisconnect` | Disconnect button |
52+
| `btnRefresh` | Refresh button |
53+
| `btnSwitchAccount` | Switch account button |
54+
| `noAccounts` | Empty accounts message |
55+
| `accountActive` | "Active" badge |
56+
| `btnActivate` | Switch button for other accounts |
57+
| `btnDeleteAccount` | Trash button tooltip |
58+
| `btnEditApiKey` | Edit API key (legacy) |
59+
| `btnUpdateApiKey` | Update button in edit-account modal |
60+
| `cancelAddAccount` | Cancel label |
61+
| `otherAccounts` | "Other accounts" heading |
62+
| `confirmDeleteAccount` | (legacy) |
63+
| `delModalTitle` | Disconnect modal title |
64+
| `delModalWarn` | Disconnect modal warning |
65+
| `cancelLabel` | Cancel button in modals |
66+
| `displayNameLabel` | Display name field label in edit-account modal |
67+
68+
### Login modal
69+
| Key | Purpose |
70+
|-----|---------|
71+
| `loginSignInTitle` | Modal title (sign-in mode) |
72+
| `loginSignInSubtitle` | Modal subtitle (sign-in mode) |
73+
| `loginCreateTitle` | Modal title (create account mode) |
74+
| `loginCreateSubtitle` | Modal subtitle (create account mode) |
75+
| `loginGoogle` | Google sign-in button |
76+
| `loginOr` | Separator label |
77+
| `loginEmailPlaceholder` | Email input placeholder |
78+
| `loginPasswordPlaceholder` | Password input placeholder |
79+
| `loginConfirmPasswordPlaceholder` | Confirm password placeholder |
80+
| `loginForgotPassword` | Forgot password link |
81+
| `loginRememberMe` | Stay signed in checkbox |
82+
| `loginNoAccount` | "Don't have an account?" |
83+
| `loginCreateAccount` | "Create account" toggle button |
84+
| `loginHaveAccount` | "Already have an account?" |
85+
| `loginResetSent` | Password reset email sent confirmation |
86+
| `loginPasswordMismatch` | Passwords don't match error |
87+
| `loginPasswordTooShort` | Password too short error |
88+
| `loginAccountCreated` | Account created confirmation |
89+
| `loginEmailInUse` | Email already registered error |
90+
91+
### Credentials card
92+
| Key | Purpose |
93+
|-----|---------|
94+
| `credTitle` | Section title |
95+
| `credEmail` | Email label |
96+
| `credApiKey` | API Key label |
97+
| `credStatus` | Status label |
98+
| `statusUntested` | Badge: untested |
99+
| `statusValid` | Badge: valid |
100+
| `statusInvalid` | Badge: invalid |
101+
| `statusChecking` | Badge: checking… |
102+
| `btnLoadInv` | Load inventory button |
103+
| `btnTestKey` | Test API key button |
104+
| `btnClearSaved` | Clear saved data button |
105+
106+
### Inventory / filters
107+
| Key | Purpose |
108+
|-----|---------|
109+
| `invTitle` | Section title |
110+
| `btnViewTable` | Table view button |
111+
| `btnViewGrid` | Grid view button |
112+
| `btnShowDeleted` | Show deleted toggle |
113+
| `btnHideDeleted` | Hide deleted toggle |
114+
| `btnExport` | Export JSON button |
115+
| `searchPlaceholder` | Search input placeholder |
116+
| `noInventory` | Empty state: no inventory |
117+
| `noMatch` | Empty state: no match |
118+
| `invLoading` | Loading spinner label |
119+
120+
### Stats
121+
| Key | Purpose |
122+
|-----|---------|
123+
| `statActive` | Active spools label (full) |
124+
| `statPlus` | TigerTag+ label |
125+
| `statDiy` | TigerTag label |
126+
| `statTotal` | Total available label |
127+
| `statActiveMini` `statPlusMini` `statDiyMini` `statTotalMini` | Collapsed sidebar labels |
128+
129+
### Table headers
130+
`thUid` `thType` `thMaterial` `thBrand` `thColor` `thName` `thWeight` `thCapacity` `thUpdated`
131+
132+
### Debug panel
133+
| Key | Purpose |
134+
|-----|---------|
135+
| `debugLabel` | Panel title |
136+
| `debugSubtitle` | Panel subtitle |
137+
| `debugNoReqs` | Empty state |
138+
139+
### Detail panel — sections
140+
`sectionColors` (plural object) `sectionPrint` `sectionWeight` `sectionLinks` `sectionContainer` `sectionDetails` `sectionRaw`
141+
142+
### Detail panel — print settings
143+
`lbNozzle` `lbBed` `lbDryTemp` `lbDryTime` `lbDensity`
144+
145+
### Weight section
146+
| Key | Purpose |
147+
|-----|---------|
148+
| `weightTotal` | Total capacity `{{cap}}` |
149+
| `weightContainer` | Container weight `{{cw}}` (also used as change-container trigger label) |
150+
| `weightOk` | Success result `{{wa}} {{w}} {{cw}}` |
151+
| `weightOkTwin` | Twin updated suffix |
152+
| `weightErr` | Error result `{{r}}` |
153+
| `weightErrComputed` | Computed weight suffix `{{c}}` |
154+
| `rawScaleLabel` | Raw scale input label |
155+
| `rawScaleHint` | Raw scale hint text |
156+
| `btnUpdate` | Update weight button |
157+
| `btnEditManually` | Toggle manual input |
158+
| `btnCloseManual` | Close manual input |
159+
| `enterNumeric` | Validation error |
160+
161+
### Container picker
162+
| Key | Purpose |
163+
|-----|---------|
164+
| `containerPickerTitle` | Modal title |
165+
| `btnChangeContainer` | Change button label / tooltip |
166+
167+
### Feedback / errors
168+
| Key | Purpose |
169+
|-----|---------|
170+
| `loadedSpools` | Plural `{{n}}` |
171+
| `invError` | Inventory load error `{{r}}` |
172+
| `invalidKey` | Key validation error `{{r}}` |
173+
| `networkError` | Generic network error |
174+
175+
### Links (detail panel)
176+
`linkYt` `linkFood`
177+
178+
### Detail rows
179+
`detUid` `detSeries` `detBrand` `detMaterial` `detDiameter` `detTagType` `detSku` `detBarcode` `detContainer` `detTwin` `detUpdated` `detManufactured`
180+
181+
### Badges
182+
`badgeRefill` `badgeRecycled` `badgeFilled` `badgeDeleted`
183+
184+
### Auto-update
185+
`updateDownloading` `updateReady` `btnRestartUpdate`
186+
187+
### Twin tag
188+
`twinBadge` `twinTitle` `twinTabThis` `twinTabTwin`
189+
190+
### Time ago
191+
`agoNow` `agoMin {{n}}` `agoHour {{n}}` `agoDay {{n}}` `agoMonth {{n}}` `agoYear {{n}}` (object with one/other in most locales)
192+
193+
### Friends system
194+
| Key | Purpose |
195+
|-----|---------|
196+
| `friendsTitle` | Section title / sidebar button label |
197+
| `friendsMyCode` | "My code" label above publicKey display |
198+
| `friendsPublicLabel` | Public inventory toggle label |
199+
| `friendsPublicSub` | Toggle sub-label ("Visible to everyone") |
200+
| `friendsList` | "My friends" section heading |
201+
| `friendsEmpty` | Empty state when no friends |
202+
| `friendsAdd` | Add friend button |
203+
| `friendRemove` | Remove friend button on each row |
204+
| `friendReqSub` | Subtitle on incoming request modal ("wants to view your inventory") |
205+
| `friendReqBlock` | Block button on request modal |
206+
| `friendReqRefuse` | Decline button on request modal |
207+
| `friendReqAccept` | Accept button on request modal |
208+
| `addFriendTitle` | Add friend modal title |
209+
| `addFriendSub` | Add friend modal subtitle |
210+
| `addFriendSend` | Send request button |
211+
| `friendSearching` | Preview state: searching |
212+
| `friendNotFound` | Preview state: no user found |
213+
| `friendSelf` | Preview state: own code entered |
214+
| `friendRequestSent` | Success message after sending |
215+
| `friendRegenConfirm` | (kept in locales, no longer used in UI — reserved) |
216+
217+
> ⚠️ This table is a snapshot and can drift as keys are added. The authoritative key set is the locale files themselves; `npm run i18n:check` is the source of truth for "do all 9 locales agree". When you add keys via `npm run i18n:add`, append them to the relevant section here too.

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tigertag-inventory",
3-
"version": "1.10.24",
3+
"version": "1.10.25",
44
"description": "Tiger Studio Manager — desktop app",
55
"main": "main.js",
66
"engines": {

0 commit comments

Comments
 (0)