create-mercato-app 0.6.6-develop.6156.1.5ac693a69a → 0.6.6-develop.6171.1.17de2dc37a

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-mercato-app",
3
- "version": "0.6.6-develop.6156.1.5ac693a69a",
3
+ "version": "0.6.6-develop.6171.1.17de2dc37a",
4
4
  "type": "module",
5
5
  "description": "Create a new Open Mercato application",
6
6
  "main": "./dist/index.js",
@@ -21,7 +21,7 @@
21
21
  "tar": "^7.5.16"
22
22
  },
23
23
  "devDependencies": {
24
- "@types/node": "^25.9.3",
24
+ "@types/node": "^26.0.0",
25
25
  "esbuild": "^0.28.1",
26
26
  "tsx": "^4.22.4",
27
27
  "typescript": "^6.0.3"
@@ -13,7 +13,7 @@
13
13
  "dev:classic": "node ./scripts/dev.mjs --classic",
14
14
  "dev:verbose": "node ./scripts/dev.mjs --verbose",
15
15
  "dev:reset": "node ./scripts/dev-reset.mjs",
16
- "build": "yarn generate && next build",
16
+ "build": "yarn generate && cross-env NODE_OPTIONS=--max-old-space-size=8192 next build",
17
17
  "start": "mercato server start",
18
18
  "lint": "next lint",
19
19
  "typecheck": "tsc --noEmit",
@@ -121,6 +121,7 @@
121
121
  "@types/node": "^25.6.0",
122
122
  "@types/react": "^19.2.14",
123
123
  "@types/react-dom": "^19.2.3",
124
+ "cross-env": "^10.1.0",
124
125
  "eslint": "^10.2.1",
125
126
  "eslint-config-next": "16.2.4",
126
127
  "jest": "^30.3.0",
@@ -133,6 +133,57 @@
133
133
  letter-spacing: 0.04em;
134
134
  cursor: pointer;
135
135
  }
136
+ .locale-control {
137
+ position: relative;
138
+ display: inline-flex;
139
+ align-items: center;
140
+ gap: 8px;
141
+ min-height: 42px;
142
+ padding: 0 36px 0 14px;
143
+ border-radius: 999px;
144
+ border: 1px solid var(--panel-border);
145
+ background: var(--surface);
146
+ color: var(--text);
147
+ cursor: pointer;
148
+ }
149
+ .locale-control::after {
150
+ content: "";
151
+ position: absolute;
152
+ right: 16px;
153
+ top: 50%;
154
+ width: 8px;
155
+ height: 8px;
156
+ border-right: 2px solid currentColor;
157
+ border-bottom: 2px solid currentColor;
158
+ transform: translateY(-65%) rotate(45deg);
159
+ pointer-events: none;
160
+ }
161
+ .locale-icon {
162
+ line-height: 1;
163
+ }
164
+ .locale-selected-label {
165
+ color: inherit;
166
+ font-size: 13px;
167
+ font-weight: 600;
168
+ letter-spacing: 0.04em;
169
+ line-height: 1;
170
+ pointer-events: none;
171
+ }
172
+ .locale-select {
173
+ position: absolute;
174
+ inset: 0;
175
+ width: 100%;
176
+ height: 100%;
177
+ border: 0;
178
+ appearance: none;
179
+ -webkit-appearance: none;
180
+ background: transparent;
181
+ color: transparent;
182
+ font: inherit;
183
+ cursor: pointer;
184
+ outline: none;
185
+ opacity: 0;
186
+ }
136
187
  .summary {
137
188
  color: var(--muted);
138
189
  font-size: 18px;
@@ -143,11 +194,14 @@
143
194
  }
144
195
  .stream-shell {
145
196
  display: grid;
197
+ grid-template-rows: auto minmax(0, 1fr);
146
198
  gap: 10px;
199
+ height: 100%;
147
200
  min-height: 0;
148
201
  }
149
202
  .hero-body {
150
203
  display: grid;
204
+ grid-template-rows: minmax(0, 1fr);
151
205
  gap: 14px;
152
206
  min-height: 0;
153
207
  overflow-y: auto;
@@ -531,7 +585,8 @@
531
585
  }
532
586
  .list {
533
587
  gap: 10px;
534
- height: clamp(176px, 22vh, 228px);
588
+ height: 100%;
589
+ min-height: 0;
535
590
  overflow-y: auto;
536
591
  padding-right: 8px;
537
592
  align-content: start;
@@ -690,7 +745,11 @@
690
745
  <div class="hero-top">
691
746
  <div class="control-row">
692
747
  <button class="control-button" id="theme-toggle" type="button">🌙 Dark</button>
693
- <button class="control-button" id="locale-toggle" type="button">🌐 EN</button>
748
+ <label class="locale-control">
749
+ <span class="locale-icon" aria-hidden="true">🌐</span>
750
+ <span class="locale-selected-label" id="locale-selected-label"></span>
751
+ <select class="locale-select" id="locale-select" aria-label="Language"></select>
752
+ </label>
694
753
  </div>
695
754
  </div>
696
755
  <div class="hero-mark" aria-hidden="true">
@@ -781,7 +840,8 @@
781
840
  const streamHeading = document.getElementById('stream-heading')
782
841
  const targetLabel = document.getElementById('target-label')
783
842
  const themeToggle = document.getElementById('theme-toggle')
784
- const localeToggle = document.getElementById('locale-toggle')
843
+ const localeSelect = document.getElementById('locale-select')
844
+ const localeSelectedLabel = document.getElementById('locale-selected-label')
785
845
  const readyUrl = document.getElementById('ready-url')
786
846
  const loginButton = document.getElementById('login-button')
787
847
  const codingShell = document.getElementById('coding-shell')
@@ -823,6 +883,7 @@
823
883
  let codingActionInFlight = false
824
884
  let gitRepoActionInFlight = false
825
885
  let codingMenuLayoutRaf = 0
886
+ let activityListLayoutRaf = 0
826
887
  const translations = {
827
888
  en: {
828
889
  badge: 'Open Mercato Dev',
@@ -1040,9 +1101,10 @@
1040
1101
  renderStaticText()
1041
1102
  })
1042
1103
 
1043
- localeToggle.addEventListener('click', () => {
1044
- const currentIndex = Math.max(0, supportedLocales.indexOf(currentLocale))
1045
- currentLocale = supportedLocales[(currentIndex + 1) % supportedLocales.length] || defaultLocale
1104
+ localeSelect.addEventListener('change', () => {
1105
+ const nextLocale = localeSelect.value
1106
+ if (!supportedLocales.includes(nextLocale)) return
1107
+ currentLocale = nextLocale
1046
1108
  localStorage.setItem(LOCALE_KEY, currentLocale)
1047
1109
  renderStaticText()
1048
1110
  })
@@ -1057,7 +1119,13 @@
1057
1119
  })
1058
1120
  window.addEventListener('resize', () => {
1059
1121
  scheduleCodingMenuLayout()
1122
+ scheduleActivityListLayout()
1060
1123
  })
1124
+ if (document.fonts?.ready) {
1125
+ document.fonts.ready.then(() => {
1126
+ scheduleActivityListLayout()
1127
+ }).catch(() => {})
1128
+ }
1061
1129
 
1062
1130
  function template(value, vars = {}) {
1063
1131
  return String(value).replace(/\{(\w+)\}/g, (_, key) => String(vars[key] ?? ''))
@@ -1073,6 +1141,15 @@
1073
1141
  return localeLabels[locale] || String(locale || '').toUpperCase()
1074
1142
  }
1075
1143
 
1144
+ function renderLocaleOptions() {
1145
+ localeSelect.replaceChildren(...supportedLocales.map((locale) => {
1146
+ const option = document.createElement('option')
1147
+ option.value = locale
1148
+ option.textContent = getLocaleLabel(locale)
1149
+ return option
1150
+ }))
1151
+ }
1152
+
1076
1153
  function splitEmoji(value) {
1077
1154
  const match = String(value ?? '').match(/^([\p{Extended_Pictographic}\u2600-\u27BF][\uFE0F]?\s*)(.*)$/u)
1078
1155
  if (!match) return { emoji: '', body: String(value ?? '') }
@@ -1147,10 +1224,12 @@
1147
1224
  streamHeading.textContent = t('streamHeading')
1148
1225
  targetLabel.textContent = t('targetLabel')
1149
1226
  terminalHint.textContent = t('terminalHint')
1150
- localeToggle.textContent = '🌐 ' + getLocaleLabel(currentLocale)
1227
+ localeSelect.value = currentLocale
1228
+ localeSelectedLabel.textContent = getLocaleLabel(currentLocale)
1151
1229
  themeToggle.textContent = currentTheme === 'dark' ? t('themeDark') : t('themeLight')
1152
1230
  renderCodingFlow(lastState)
1153
1231
  renderGitRepoFlow(lastState)
1232
+ scheduleActivityListLayout()
1154
1233
  }
1155
1234
 
1156
1235
  function formatActivityTimestamp(value) {
@@ -1163,9 +1242,28 @@
1163
1242
  }).format(date)
1164
1243
  }
1165
1244
 
1245
+ function scheduleActivityListLayout() {
1246
+ if (activityListLayoutRaf) {
1247
+ window.cancelAnimationFrame(activityListLayoutRaf)
1248
+ }
1249
+ activityListLayoutRaf = window.requestAnimationFrame(() => {
1250
+ activityListLayoutRaf = 0
1251
+ updateActivityListLayout()
1252
+ })
1253
+ }
1254
+
1255
+ function updateActivityListLayout() {
1256
+ activityList.dataset.overflowing = 'true'
1257
+ const overflowing = activityList.scrollHeight > activityList.clientHeight + 1
1258
+ activityList.dataset.overflowing = overflowing ? 'true' : 'false'
1259
+ if (overflowing) {
1260
+ activityList.scrollTop = activityList.scrollHeight
1261
+ }
1262
+ }
1263
+
1166
1264
  function renderActivities(items) {
1167
1265
  if (!Array.isArray(items) || items.length === 0) return
1168
- const ordered = items.slice().reverse()
1266
+ const ordered = items.slice()
1169
1267
  activityList.innerHTML = ordered.map((item) => {
1170
1268
  const key = String(item ?? '')
1171
1269
  if (!activitySeenAt.has(key)) {
@@ -1176,6 +1274,7 @@
1176
1274
  const safeTimestamp = escapeHtml(timestamp)
1177
1275
  return '<li><div class="activity-entry"><span class="activity-time">' + safeTimestamp + '</span><span class="activity-message">' + safeMessage + '</span></div></li>'
1178
1276
  }).join('')
1277
+ scheduleActivityListLayout()
1179
1278
  }
1180
1279
 
1181
1280
  function renderFailure(state) {
@@ -1598,6 +1697,7 @@
1598
1697
  currentLocale = detectLocale()
1599
1698
  currentTheme = detectTheme()
1600
1699
  applyTheme()
1700
+ renderLocaleOptions()
1601
1701
  renderStaticText()
1602
1702
  refresh()
1603
1703
  setInterval(refresh, 1000)