@escape-game-over/atlas 0.1.99 → 0.1.101
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/astro/client.ts +3 -0
- package/src/contact-form.ts +3 -1
- package/src/hours.ts +74 -40
- package/src/index.ts +3 -0
package/package.json
CHANGED
package/src/astro/client.ts
CHANGED
package/src/contact-form.ts
CHANGED
|
@@ -28,8 +28,10 @@ export type ContactFormType =
|
|
|
28
28
|
| "birthday_party"
|
|
29
29
|
| "board_games"
|
|
30
30
|
| "group_booking"
|
|
31
|
+
| "school_trips"
|
|
31
32
|
| "team_building"
|
|
32
|
-
| "voucher"
|
|
33
|
+
| "voucher"
|
|
34
|
+
| "vr_games";
|
|
33
35
|
|
|
34
36
|
/** Where a deployment's contact mail goes. */
|
|
35
37
|
export interface MailEndpoint {
|
package/src/hours.ts
CHANGED
|
@@ -164,6 +164,13 @@ export function groupHours(
|
|
|
164
164
|
return [...groups.values()];
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Which clock times print on: `"h23"` as written (`14:00`), `"h12"` on a
|
|
169
|
+
* 12-hour clock (`2:00 PM`). Never the locale's default, which gives Greek a
|
|
170
|
+
* 12-hour clock nobody there uses on a door.
|
|
171
|
+
*/
|
|
172
|
+
export type HourCycle = "h12" | "h23";
|
|
173
|
+
|
|
167
174
|
/**
|
|
168
175
|
* How to print a week. Day names come from `Intl` in `locale`; "closed" is
|
|
169
176
|
* copy, so the caller translates it.
|
|
@@ -175,12 +182,8 @@ export interface HoursFormat {
|
|
|
175
182
|
weekday?: "short" | "long";
|
|
176
183
|
/** The word for a day the venue is shut. */
|
|
177
184
|
closed: string;
|
|
178
|
-
/**
|
|
179
|
-
|
|
180
|
-
* Not the locale's default, which gives Greek a 12-hour clock nobody there
|
|
181
|
-
* uses on a door.
|
|
182
|
-
*/
|
|
183
|
-
hourCycle?: "h12";
|
|
185
|
+
/** As written (`"h23"`) when absent. */
|
|
186
|
+
hourCycle?: HourCycle;
|
|
184
187
|
/** Between the ends of a span: `Mon–Thu`, `14:00–23:30`. */
|
|
185
188
|
between?: string;
|
|
186
189
|
/** Between spans: `Mon–Thu, Sun`. */
|
|
@@ -226,17 +229,41 @@ export function formatHours(
|
|
|
226
229
|
}));
|
|
227
230
|
}
|
|
228
231
|
|
|
232
|
+
/** How to say a week in a sentence: `HoursFormat` without its separators. */
|
|
233
|
+
export type HoursSentenceFormat = Omit<HoursFormat, "and">;
|
|
234
|
+
|
|
229
235
|
/**
|
|
230
|
-
*
|
|
231
|
-
*
|
|
236
|
+
* Each language's semicolon, between one group of days and the next. `Intl`
|
|
237
|
+
* has no list form for it, and it is punctuation rather than copy, so it lives
|
|
238
|
+
* here. A language missing from this table throws rather than borrowing the
|
|
239
|
+
* English one: add it here.
|
|
232
240
|
*/
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
241
|
+
const SEMICOLONS: Readonly<Record<string, string>> = {
|
|
242
|
+
ar: "؛ ",
|
|
243
|
+
de: "; ",
|
|
244
|
+
el: "· ",
|
|
245
|
+
en: "; ",
|
|
246
|
+
es: "; ",
|
|
247
|
+
// A narrow no-break space before it, as French sets it.
|
|
248
|
+
fr: "\u202F; ",
|
|
249
|
+
hu: "; ",
|
|
250
|
+
it: "; ",
|
|
251
|
+
pt: "; ",
|
|
252
|
+
ru: "; ",
|
|
253
|
+
sv: "; ",
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
function semicolonFor(locale: string): string {
|
|
257
|
+
const { language } = new Intl.Locale(locale);
|
|
258
|
+
const semicolon = Object.hasOwn(SEMICOLONS, language)
|
|
259
|
+
? SEMICOLONS[language]
|
|
260
|
+
: undefined;
|
|
261
|
+
if (semicolon === undefined) {
|
|
262
|
+
throw new Error(
|
|
263
|
+
`hoursSentence has no semicolon for "${language}" (${locale}). Add it to SEMICOLONS in hours.ts.`
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
return semicolon;
|
|
240
267
|
}
|
|
241
268
|
|
|
242
269
|
/**
|
|
@@ -245,13 +272,15 @@ export interface HoursSentenceFormat extends Omit<HoursFormat, "and"> {
|
|
|
245
272
|
*
|
|
246
273
|
* Days and times join with the locale's own "and" (`Intl.ListFormat`), so a
|
|
247
274
|
* sentence in Arabic reads `الاثنين–الخميس والأحد` rather than borrowing an
|
|
248
|
-
* English comma
|
|
275
|
+
* English comma; groups with the language's semicolon (`؛` in Arabic). No
|
|
276
|
+
* closing full stop: the copy around it decides that.
|
|
249
277
|
*/
|
|
250
278
|
export function hoursSentence(
|
|
251
279
|
hours: WeeklyHours,
|
|
252
280
|
format: HoursSentenceFormat
|
|
253
281
|
): string {
|
|
254
282
|
const between = format.between ?? "–";
|
|
283
|
+
const semicolon = semicolonFor(format.locale);
|
|
255
284
|
const { dayName, time } = printer(format);
|
|
256
285
|
const list = new Intl.ListFormat(format.locale, {
|
|
257
286
|
type: "conjunction",
|
|
@@ -275,7 +304,34 @@ export function hoursSentence(
|
|
|
275
304
|
);
|
|
276
305
|
return `${days} ${times}`;
|
|
277
306
|
})
|
|
278
|
-
.join(
|
|
307
|
+
.join(semicolon);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** How `formatTime` prints a time. */
|
|
311
|
+
export interface TimeFormat {
|
|
312
|
+
/** The language the clock is read in, e.g. `"en-US"`. */
|
|
313
|
+
readonly locale: string;
|
|
314
|
+
/** As written (`"h23"`) when absent. */
|
|
315
|
+
readonly hourCycle?: HourCycle;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* One time as the hours print it: as written (`14:00`), or on a 12-hour clock
|
|
320
|
+
* (`2:00 PM`). For a line that quotes a single time, such as "open until",
|
|
321
|
+
* so it reads like the table beside it.
|
|
322
|
+
*/
|
|
323
|
+
export function formatTime(at: TimeOfDay, format: TimeFormat): string {
|
|
324
|
+
if (format.hourCycle !== "h12") return at;
|
|
325
|
+
return new Intl.DateTimeFormat(format.locale, {
|
|
326
|
+
hour: "numeric",
|
|
327
|
+
minute: "2-digit",
|
|
328
|
+
hourCycle: "h12",
|
|
329
|
+
timeZone: "UTC",
|
|
330
|
+
}).format(
|
|
331
|
+
new Date(
|
|
332
|
+
Date.UTC(2024, 0, 1, Number(at.slice(0, 2)), Number(at.slice(3, 5)))
|
|
333
|
+
)
|
|
334
|
+
);
|
|
279
335
|
}
|
|
280
336
|
|
|
281
337
|
/** Day names and times as `format` prints them. */
|
|
@@ -289,29 +345,7 @@ function printer(
|
|
|
289
345
|
});
|
|
290
346
|
const dayName = (day: Weekday): string =>
|
|
291
347
|
names.format(new Date(Date.UTC(2024, 0, 1 + WEEK.indexOf(day))));
|
|
292
|
-
const
|
|
293
|
-
format.hourCycle === "h12"
|
|
294
|
-
? new Intl.DateTimeFormat(format.locale, {
|
|
295
|
-
hour: "numeric",
|
|
296
|
-
minute: "2-digit",
|
|
297
|
-
hourCycle: "h12",
|
|
298
|
-
timeZone: "UTC",
|
|
299
|
-
})
|
|
300
|
-
: undefined;
|
|
301
|
-
const time = (at: TimeOfDay): string =>
|
|
302
|
-
clock === undefined
|
|
303
|
-
? at
|
|
304
|
-
: clock.format(
|
|
305
|
-
new Date(
|
|
306
|
-
Date.UTC(
|
|
307
|
-
2024,
|
|
308
|
-
0,
|
|
309
|
-
1,
|
|
310
|
-
Number(at.slice(0, 2)),
|
|
311
|
-
Number(at.slice(3, 5))
|
|
312
|
-
)
|
|
313
|
-
)
|
|
314
|
-
);
|
|
348
|
+
const time = (at: TimeOfDay): string => formatTime(at, format);
|
|
315
349
|
return { dayName, time };
|
|
316
350
|
}
|
|
317
351
|
|
package/src/index.ts
CHANGED
|
@@ -120,13 +120,16 @@ export {
|
|
|
120
120
|
type DayHours,
|
|
121
121
|
type FormattedHours,
|
|
122
122
|
formatHours,
|
|
123
|
+
formatTime,
|
|
123
124
|
groupHours,
|
|
125
|
+
type HourCycle,
|
|
124
126
|
type HoursFormat,
|
|
125
127
|
type HoursGroup,
|
|
126
128
|
type HoursSentenceFormat,
|
|
127
129
|
hoursSentence,
|
|
128
130
|
type OpenStatus,
|
|
129
131
|
openStatus,
|
|
132
|
+
type TimeFormat,
|
|
130
133
|
type TimeOfDay,
|
|
131
134
|
type TimeRange,
|
|
132
135
|
type VenueNow,
|