mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-13 07:40:59 +00:00
52f0fb882f
The screens the app ships itself (welcome, plans, address, own server and the states between) move from the dark card layout to a light design on an animated aerial landscape drawn by a WebGL shader (native-shell/scenery.ts): an island, a coastal town, farmland and mountains in one world. - Welcome: the landscape with the TREK wordmark, three perks in one card, "Explore cloud plans" and "I already have a TREK" as two buttons. - Plans: one tab per plan; choosing one flies the camera to its place, further inland with every plan. Each plan reads as a kind of trip, the price sits in a card with a monthly/yearly switch and counts to its new amount in the store's own format (native-shell/amount.ts), and a yearly price shows what it makes a month. Restore purchases, the renewal terms and the links stay as the store rules require. - Address: the address writes itself on a glass card over the landscape; free, the password rules and the agreement sit on white cards. - Own server: the server address on the glass card; a failed check turns the card red with what went wrong, proxy sign-in and client certificate panels in the same style. - States: server not reachable, certificate needed, already subscribed, setting up (with its steps, then "Arrived") and the slow setup. - iPad, an unfolded phone and a phone on its side get two columns, the landscape beside the content; on a dual-screen device each half takes one screen. Arabic and Hebrew mirror through logical sides only. - The shader caps the pixel ratio at 2, drops to a lower resolution on a slow device, stops in the background and is one still frame with reduced motion. - The sign-in and error page bars over a proxy's page (iOS and Android) take the same look: a white card and a dark button. - Plus Jakarta Sans is bundled for the text, with Montserrat standing in for Cyrillic; the wordmark fonts and the old preview images are gone. - New strings in all 28 languages; the keys of the old screens removed. - The dev sample plans follow the cloud's plans (start, basis, plus, pro).
44 lines
1.9 KiB
TypeScript
44 lines
1.9 KiB
TypeScript
/**
|
||
* The amount inside a price as the store writes it ("4,90 €", "$4.99",
|
||
* "CHF 12.90", "1.290 ₽"), and a way to write another amount the same way: the
|
||
* same currency, the same decimal mark, the same digit grouping. The plan picker
|
||
* counts a price up to its new value with it, and turns a yearly price into what
|
||
* it makes a month, without knowing the store's locale.
|
||
*/
|
||
interface Amount {
|
||
/** The amount as a number, in the price's own unit (4.9 for "4,90 €"). */
|
||
value: number;
|
||
/** The price written for another amount, in the same format. */
|
||
render(value: number): string;
|
||
}
|
||
|
||
// Digits with the marks stores put between them: . , space, no-break spaces, and
|
||
// the apostrophes Swiss formats group thousands with (1'290 and 1’290).
|
||
const NUMBER = /\d[\d.,\s '’]*\d|\d/;
|
||
|
||
export function amountIn(label: string): Amount | null {
|
||
const match = NUMBER.exec(label);
|
||
if (!match) return null;
|
||
const raw = match[0];
|
||
// The decimal mark is the last . or , followed by one or two digits to the end.
|
||
const decimal = /([.,])(\d{1,2})$/.exec(raw);
|
||
const decimals = decimal ? decimal[2].length : 0;
|
||
const mark = decimal ? decimal[1] : '';
|
||
const whole = decimal ? raw.slice(0, raw.length - decimal[0].length) : raw;
|
||
const group = /[.,\s '’]/.exec(whole)?.[0] ?? '';
|
||
const digits = whole.replace(/\D/g, '') + (decimal ? `.${decimal[2]}` : '');
|
||
const value = Number(digits);
|
||
if (!Number.isFinite(value)) return null;
|
||
const before = label.slice(0, match.index);
|
||
const after = label.slice(match.index + raw.length);
|
||
return {
|
||
value,
|
||
render(next: number) {
|
||
const fixed = Math.max(0, next).toFixed(decimals);
|
||
const [int, frac] = fixed.split('.');
|
||
const grouped = group ? int.replace(/\B(?=(\d{3})+(?!\d))/g, group) : int;
|
||
return `${before}${grouped}${frac !== undefined ? mark + frac : ''}${after}`;
|
||
},
|
||
};
|
||
}
|