Skip to content

Commit ffd153b

Browse files
committed
stable update time, fix marked load issue
1 parent 44ebd7d commit ffd153b

6 files changed

Lines changed: 43 additions & 53 deletions

File tree

app/data/yaml2json.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import argparse
55
import json
6+
from datetime import datetime, timezone
67
from pathlib import Path
78

89
try:
@@ -116,6 +117,27 @@ def convert_yaml_to_json(yaml_path, tag_delimiter):
116117
json.dump(cards, handle, indent=2, ensure_ascii=False)
117118
handle.write('\n')
118119

120+
write_metadata(json_path)
121+
122+
123+
def write_metadata(json_path: Path) -> None:
124+
project_root = json_path.parent.parent
125+
metadata_path = project_root / 'src' / 'cards-metadata.js'
126+
127+
try:
128+
last_modified = datetime.fromtimestamp(json_path.stat().st_mtime, tz=timezone.utc)
129+
except OSError as exc:
130+
print(f'Unable to stat {json_path}: {exc}')
131+
last_modified = None
132+
133+
metadata_path.parent.mkdir(parents=True, exist_ok=True)
134+
with metadata_path.open('w', encoding='utf-8') as handle:
135+
if last_modified:
136+
iso_value = last_modified.isoformat(timespec='seconds').replace('+00:00', 'Z')
137+
handle.write(f"export const cardsLastModified = '{iso_value}';\n")
138+
else:
139+
handle.write('export const cardsLastModified = null;\n')
140+
119141

120142
def main():
121143
parser = argparse.ArgumentParser(description='Generate data/cards.json from a YAML source file.')

app/src/cards-metadata.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const cardsLastModified = '2025-10-22T01:00:14Z';

app/src/cards.js

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
let cardsCache = null;
22

3-
const cardsImportPath = '../data/cards.json';
4-
53
const cardsRequestUrl = (() => {
64
try {
7-
return new URL(cardsImportPath, import.meta.url).href;
5+
return new URL('../data/cards.json', import.meta.url).href;
86
} catch (error) {
97
console.warn('Unable to resolve cards.json via import.meta.url, falling back to relative path', error);
108
return 'data/cards.json';
@@ -112,27 +110,26 @@ function shuffleCards(cards) {
112110
return shuffled;
113111
}
114112

115-
async function loadFromImport() {
113+
function loadFromBundle() {
114+
if (typeof import.meta.glob !== 'function') {
115+
return null;
116+
}
117+
116118
try {
117-
const module = await import(cardsImportPath, { assert: { type: 'json' } });
119+
const modules = import.meta.glob('../data/cards.json', { eager: true });
120+
const module = modules['../data/cards.json'];
121+
if (!module) {
122+
return null;
123+
}
124+
118125
const payload = module.default ?? module;
119126
if (!Array.isArray(payload)) {
120127
return null;
121128
}
122129

123130
return payload;
124131
} catch (error) {
125-
try {
126-
const module = await import(cardsImportPath);
127-
const payload = module.default ?? module;
128-
if (!Array.isArray(payload)) {
129-
return null;
130-
}
131-
132-
return payload;
133-
} catch (nestedError) {
134-
console.warn('Falling back to network fetch for cards', nestedError);
135-
}
132+
console.warn('Unable to load cards bundle via import.meta.glob', error);
136133
return null;
137134
}
138135
}
@@ -167,9 +164,9 @@ export async function fetchCards() {
167164
return cardsCache;
168165
}
169166

170-
const imported = await loadFromImport();
171-
if (imported && imported.length > 0) {
172-
cardsCache = prepareCards(imported, { shuffle: true });
167+
const bundled = loadFromBundle();
168+
if (bundled && bundled.length > 0) {
169+
cardsCache = prepareCards(bundled, { shuffle: true });
173170
return cardsCache;
174171
}
175172

app/src/main.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
/* global __CARDS_LAST_MODIFIED__ */
21
import { fetchCards, renderCardGrid, prepareCards } from './cards.js';
2+
import { cardsLastModified } from './cards-metadata.js';
33
import { createModalController } from './modal.js';
44

55
const app = document.getElementById('app');
@@ -24,8 +24,7 @@ if (siteUpdate) {
2424
timeStyle: 'short',
2525
});
2626

27-
const lastUpdatedSource = typeof __CARDS_LAST_MODIFIED__ !== 'undefined' ? __CARDS_LAST_MODIFIED__ : null;
28-
const parsedLastUpdated = typeof lastUpdatedSource === 'string' ? new Date(lastUpdatedSource) : null;
27+
const parsedLastUpdated = typeof cardsLastModified === 'string' ? new Date(cardsLastModified) : null;
2928
const resolvedDate = parsedLastUpdated && !Number.isNaN(parsedLastUpdated.getTime())
3029
? parsedLastUpdated
3130
: new Date();

app/src/modal.js

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
const MARKED_CDN_URL = 'https://cdn.jsdelivr.net/npm/marked@16.4.1/lib/marked.esm.js';
2-
31
let markedPromise = null;
42

53
function resolveMarkedInstance() {
@@ -13,18 +11,8 @@ function resolveMarkedInstance() {
1311
return existing;
1412
}
1513

16-
try {
17-
const module = await import('marked');
18-
const candidate = module.marked ?? module.default ?? module;
19-
if (candidate && typeof candidate.parse === 'function') {
20-
return candidate;
21-
}
22-
} catch (error) {
23-
console.warn('Falling back to CDN marked import', error);
24-
}
25-
26-
const fallback = await import(MARKED_CDN_URL);
27-
const candidate = fallback.marked ?? fallback.default ?? fallback;
14+
const module = await import('marked');
15+
const candidate = module.marked ?? module.default ?? module;
2816
if (!candidate || typeof candidate.parse !== 'function') {
2917
throw new Error('Unable to load marked parser');
3018
}

app/vite.config.js

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,5 @@
11
import { defineConfig } from 'vite';
22
import { resolve } from 'node:path';
3-
import { statSync } from 'node:fs';
4-
5-
function resolveCardsLastModified() {
6-
try {
7-
const stats = statSync(resolve(__dirname, 'data/cards.json'));
8-
return stats.mtime.toISOString();
9-
} catch (error) {
10-
console.warn('Unable to stat data/cards.json for last modified timestamp', error);
11-
return null;
12-
}
13-
}
14-
15-
const cardsLastModified = resolveCardsLastModified();
16-
173
export default defineConfig({
184
root: '.',
195
base: './',
@@ -28,7 +14,4 @@ export default defineConfig({
2814
preview: {
2915
open: true,
3016
},
31-
define: {
32-
__CARDS_LAST_MODIFIED__: cardsLastModified ? JSON.stringify(cardsLastModified) : 'null',
33-
},
3417
});

0 commit comments

Comments
 (0)