summaryrefslogtreecommitdiff
path: root/modules/orgflow-ui/src/wasmJsMain
AgeCommit message (Collapse)Author
2026-09-26Calendar: today-relative offsets, re-entering the month view, and a working ↵charlie
pie layout +"-1"/"+1" is information about distance from today, not a step button. The row now reads 今日から -21日 (or +N日) - how far the centre date is from today - and pressing it returns to today. Showing it as a step control gave no sense of distance, which was the point of the row. The same row now exists on the month and year levels, in the unit that fits: 今月から +Nヶ月 and 今年から +N年. It is omitted when the value is zero, since the centre already shows the current month or year and repeating it says nothing. Re-entering the month view. key(f) only re-keys when the frame changes, so pressing Calendar while already in Calendar did nothing - the state survived. A reentry counter is now part of the key, so pressing the same frame again resets it to the default view. That fixes the case the previous fix missed. The pie menu labels are finally placed correctly, after two wrong approaches that are worth recording because the failure was invisible in the code: 1. Computing offsets from the centre. Modifier.offset moves a node from where layout put it, so with a centre-aligned parent every label was displaced by half the parent's size. Only one of four appeared. 2. A nested Box(fillMaxSize()) with per-slot Alignment. The inner box takes the window's size rather than the parent's, so labels were drawn far from the disc and nothing appeared near it. Both failed for the same reason: the offset origin depends on the parent's dimensions, which cannot be corrected with constants. The fix is to stop computing positions and let layout do it - a Row of [label column, disc, label column], each column a Column of two labels. The disc and its labels cannot drift apart now because they are siblings in the same layout. Month and year labels carried the same defect and are fixed by the same change, since they all go through PieDial. Also fixed a compile break of my own making, worth noting because it presented as something unrelated: the file stopped compiling with "Unresolved reference" on functions that plainly exist. The cause was a doubled /** - two doc-comment openers in a row - which left one unterminated, so everything after it parsed as comment. This is the second time a comment has caused a cascade of unrelated errors in this file; Kotlin's nested comments mean an accidental /* anywhere, including inside a comment, swallows the rest of the file.
2026-09-26Calendar: fix the day-view header, month labels, year day taps, and the pie ↵charlie
labels Seven items, one of which was a real bug with a clear cause. Calendar would not return to the month view. Calling CalendarFrame() from a when(f) means Compose keeps its remember blocks alive when you navigate away, so leaving in the year or day view and coming back left you in that view. Wrapping the frames in key(f) gives each frame its own state, so Calendar always opens at the month view per 2.27. The day view header is now the requested shape: the centre is the date being viewed, written the same way the body used to write it (9月26日(土)), and the row below carries the offset from today as pressable chips. Pressing them moves. The offset is measured from today, not from the day being viewed - with today+3 on screen the row reads [今日] [-1日] [+1日] and those go to today, +2 and +4. Showing the current day again in that row would duplicate the centre. The first version of this did get the arithmetic wrong, sending +N back to the same day; caught and fixed while wiring it. The same bar shape is used for all three levels: chevron, centred value, chevron, and a pill on the month view. The month pill says 今月, not 今日 - the day view is the one that says today. Month event-bar labels were squashed: 9sp text in a 16dp bar left no vertical padding at all. The bar is 20dp, the text 10sp with a 12sp line height, and 4dp of horizontal inset. Days with more than one event keep plain 5dp colour bars - there is not enough height per bar for legible text, and colour alone beats unreadable text. Year view day taps now work. The previous version deliberately made days non-tappable to keep the year level about picking a month; the request was to jump to a day directly, so tapping a day in the year view opens that day. Spacing between sections, grounded in a measurement rather than a convention. Brumby & Zhuang 2015 (CHI, DOI 10.1145/2702123.2702177 - open access, read in full) measured 30px between items in a column and 250px between column groups, about 1:8, and concluded that what actually governs search time is whether the visual groups match the semantic ones - grouping unrelated items visually slowed search down (M=3.34s semantically arranged vs M=4.23s random, p<.001). This app had 6dp between rows and 16dp between sections, only 1:2.7. Sections are now 48dp for 1:8. The paper measured a ratio, not absolute values, so only the ratio is borrowed and the absolute size follows the row height here - which is more to stand on than 8dp-grid conventions: a survey found that Gestalt proximity gives only a monotonic relation and that the 8dp grid, 44pt and 48dp+8dp figures are industry conventions with no measurement study cited behind them. Pie menu quadrant labels are now always visible, placed outside the circle at 1.15x the radius. They were previously only shown while held, to avoid the occlusion that Callahan et al. 1988 (DOI 10.1145/57167.57182) recorded users complaining about - but an always-present control with no labels gives no reason to reach for it. Keeping them outside means the disc, its bands and the centre W are still never covered. Checked and NOT reproduced: black text in dark mode on Home, Timeline and Note. The most recent captures of all three were read carefully and every string is white or light grey. 2.31's spacing change is the only edit those frames received in this pass. If specific text still reads as black, it needs a screenshot that names it.
2026-09-26Phone layout: tab icons, short labels, and a working way to shoot at phone widthcharlie
The narrow layout was already implemented to 2.22's skeleton, but measuring it at a real phone width found two problems, and getting to that measurement took three failed approaches worth recording. Why a Galaxy S25 user agent changed nothing: Firefox will not make a window narrower than 500 CSS px. Requesting 380/400/412/450/500 returned 500 every time, while 600 and 700 were honoured exactly. An S25 is 384-412 px, so the real width is unreachable in a top-level window - the limit is the window, not the UA. Shrinking the Compose canvas element to 384 also failed: the canvas attribute became 384 but Compose kept laying out against 500, so the capture showed 500-wide content cut off at 384 and the tab bar lost Live and settings off the right edge. What works is an iframe of the exact size - it has its own viewport, so the app inside sees innerWidth 384 and Compose lays out against real dimensions. phone-host.html is now part of the web resources so it ships with the bundle, and shot-phone.py drives it. Recorded as 2.29 so this is not re-derived later. With a true 384px viewport, the tab bar did not fit. Laying labels out with SpaceEvenly got only Home, Timeline, Calendar and Note on screen; Live and settings were pushed off and never drawn. Six text labels do not fit 384px. So the tabs are now an icon over a short label, each weighted equally (2.28): - icons drawn on a Canvas, no image assets: house, list, calendar, page, camera, gear - short labels, chosen rather than truncated - cutting a word mid-way makes it unreadable, so separate short names are used: Home / Line / Cal / Note / Live / Settings - labels stay English. One tab reading 設定 among five English ones mixes languages inside a single row; in-page headings stay Japanese, but the tab row is a list of proper names. - icons are never shown alone, for the same reason 2.22 rejected an icon-only nav: NN/g's Icon Usability (2014) found icons on their own do not convey meaning reliably. Wide layout gets the same six glyphs on the left-column nav, as asked. The same frame now looks the same at both widths, so nothing has to be relearned when the window changes; wide has room for the full words, so it keeps "Timeline" and "Calendar". Calendar bar, per the same request: the centre pill on the month view is now 今月 rather than 今日 (the day view keeps 今日), and the pill is drawn with a fill so it reads as pressable rather than as a heading. Both bars were re-measured at 384px and fit. One capture trap worth knowing: the browser profile is reused so the wasm caches and startup is fast, which means a stale build can be served and the screenshot silently shows the previous version - it did, showing "Time" and "設定" after those strings had already changed. The URL now carries a cache-buster that the harness forwards to the inner iframe.
2026-09-26Wasm shell: fix the Japanese font lookup so text renderscharlie
The web shell never loaded its font. webfont.js stores the bundled TTF as base64 in window.__orgflowFontB64, but the fetch/XHR shim in index.html only looked for globalThis.__orgflowFontBlobs, which nothing ever created. Every font request therefore fell through to the real fetch, the nested composeResources path does not exist on the deploy server (its FTP forbids MKD, which is why the font is shipped flat in the first place), and the app rendered with no font at all. Visible effect: every date number and every Japanese label came out as tofu boxes. Confirmed by capturing the running app - document.fonts reported "loaded n=0", and the calendar grid showed squares where the digits belong. Fix: decode __orgflowFontB64 into the Blob map the shim expects. The decode runs once at parse time and again lazily on the first matching request, because webfont.js is loaded after this script and may not have run yet when the first font read happens. Two other things were established while chasing this, and are worth recording because they look like application bugs but are not: - The month grid appeared to stop at the 19th. It was not a layout bug: the browser chrome left only 650px of viewport, and a 7-column month grid needs roughly 190px per row, so six rows cannot fit. The screenshot tool now runs the browser in kiosk mode and sizes it to the full screen (1280x1024), and the grid shows the whole month plus the out-dates. - The calendar's "today" cell looked like a two-cell red block in one capture. It is a single cell; the earlier reading was off because the viewport was small and the cells were being squeezed.
2026-09-24UI: stop calling kotlinx-datetime's now()/todayIn() - it cannot link on WasmCharlie Root
The UI still died at startup, now with a different symbol: IrLinkageError: Function 'now' can not be called: No function found for symbol 'com.kizitonwose.calendar.core/now|now@kotlinx.datetime.LocalDate.Companion( kotlin.time.Clock;kotlinx.datetime.TimeZone){}[0]' So replacing the calendar library's YearMonth.now() with LocalDate.now() was not a fix - it only moved the failure one level down. Every now/todayIn entry point in this stack is declared as taking a kotlin.time.Clock, and that symbol does not resolve in this combination (Kotlin 2.1.21 + kotlinx-datetime 0.7.1 + Compose MP 1.8.2, Wasm target). kotlin.time.Clock only becomes usable in later Kotlin versions, and kotlinx-datetime 0.7 is built against that newer shape. Get "today" from the platform instead: a new expect/actual todayLocalDate() with one actual per target - JS Date on wasmJs, Clock.System.todayIn() on jvm and android (where the Clock symbol does resolve). The calendar month is then built as YearMonth(year, monthNumber) from that date, which also avoids the kizitonwose Month vs kotlinx Month type clash that broke the Android compile. Wasm js(...) has its own constraint worth recording: the call must be the single expression forming a top-level function body, and the result must be a primitive/string/function - so the Date reads are folded into one arrow IIFE returning YYYYMMDD as an Int, which Kotlin then splits. Verified: compileKotlinWasmJs now passes.
2026-09-24UI: wine/ink palette with a dark default, icon pie rendered per 2.5.1, and ↵Charlie Root
button-shaped search and controls Colour (per user direction: "black background with white, and wine instead of black"): the theme now has a dark default - ink (near-black) ground, warm off-white text - with wine as the accent, and a light variant where the same wine becomes the primary against a pale grey ground with white surfaces. Purple is gone entirely. The [D/L] control in the bottom-left cluster toggles between them, and Main.kt holds the appearance state. The wine itself was desaturated and deepened (0xFF6E1B2E -> 0xFF8C2438 for the dark ground) so it reads as wine rather than a flat red on either ground. Pie: the previous attempt got this wrong. Per 2.5.1's drawing (2026-09-22, fixed) the pie is ONE circle divided by a cross into four quadrants, with the centre labelled W (whole); the quadrants are the top-level scopes plus the personal scope, which is pinned as its own quadrant because it sits outside the organisation tree. The implementation had instead lined up three separate circles beside the centre, which is not the specified shape at all. 2.19 also fixes the interaction: there is no "open" gesture (touch and drag), the centre is always whole regardless of where you press, the touched quadrant highlights while the others dim, release commits, dragging outward expands to the concrete children with a spoke reaching outside the circle, and returning to the centre cancels to whole. PieMenu.kt now draws that single cross-divided circle as an icon (Canvas arcs, dimmed/selected states, W in the centre) and tracks drag position to quadrant, committing on release. The outward expansion to concrete children and the 150-200ms expand / 100ms contract animation from 2.19 are the next step and are marked as such in the file. Chrome: search and the bottom-left controls are buttons now instead of bracketed text - a rounded search button with a glyph, and circular +, D/L, gear buttons. The narrow form's FAB is the same circular button. Also fixed here: CalendarFrame no longer calls YearMonth.now(). The Wasm build compiled it but the runtime died on load with IrLinkageError: Function 'now' can not be called: No function found for symbol 'com.kizitonwose.calendar.core/YearMonth.Companion.now' The symbol requires kotlin.time.Clock, which this Kotlin version does not resolve for that library's binary, so the calendar library''s now() is unusable here; building the YearMonth from LocalDate.now() gives the same value without it.
2026-09-24UI: implement the five-frame FSMP shell (2.22) with a month calendar, and ↵Charlie Root
add the Calendar CMP library The UI module previously held a single welcome card. It now implements the fixed skeleton from the FSMP front-end design (section 2.22, decided 2026-09-24) as Compose Multiplatform code shared by every target: Home now: TODO chips + today (timetable / same-day notices / deadlines) Timeline flow: posts with answer/confirm badges and contact bubbles Calendar when: month grid -> tap a day -> day timeline (hour-axis rows mixing timetable and auto-source events, per 2.21) Note what remains: notes / tasks / documents / artefacts with WorkType filters and the unsubmitted view Live now-connect: live / scheduled / recordings, teacher start button Chrome follows the decided responsive rules rather than invented layout: the wide form gets the left rail (title + date/period, search, the five frames in the fixed order Home/Timeline/Calendar/Note/Live, spacer, [+][gear][D/L] at the bottom), the narrow form gets a search field on top and a bottom tab bar with the gear at its right end. The pie sits bottom-right on both forms (centre W, four quadrants) and the [+] sits at its left as a pair, swapping under the left-handed flip setting; the contact input bar appears only on wide Timeline and carries no destination chip, because the pie itself shows scope and destination. Frame bodies intentionally hold sample values - the design leaves in-frame placement and visual tuning to this prototype, so only the skeleton is asserted. Calendar dependency: kizitonwose/Calendar (MIT), artifact com.kizitonwose.calendar:compose-multiplatform, which supports Android/iOS/js/ WasmJs/Desktop like the rest of the build. Pinned to 2.7.0 because that is the release whose required Kotlin (2.1.21) matches this project; 2.8.0 needs Kotlin 2.2 and 2.10.x needs Kotlin 2.3 plus Compose 1.10, so either would force a toolchain upgrade well beyond this change. One trap worth recording: the library carries its OWN YearMonth (com.kizitonwose.calendar.core.YearMonth, with its own now()/plusMonths()/ minusMonths() extensions) because kotlinx-datetime 0.6.2 - the version the library declares - has no YearMonth at all. That type only landed in kotlinx-datetime 0.7.0, which is what this project uses. Importing kotlinx.datetime.YearMonth therefore compiles to a type mismatch inside rememberCalendarState; the code must use the library's type. Do not "fix" this by forcing kotlinx-datetime upward - the library's binary is bound to the 0.6.2 shape.
2026-09-03kukuri reset: welcome-only app shell + bridge/vendor modules + CI infraketsuban
Full pre-reset history preserved on branch backup/full-pre-reset (2ccab79).