Skip to content

Commit 3e02f91

Browse files
priyanshu92Copilot
andcommitted
restore scaffold toast dismiss
Restore the close button for create-site scaffold input banners across React, Vue, Angular, and Astro loaders. - Track dismissed prompts so closing the banner hides only the current prompt - Reset dismissal when awaitingInput clears so later prompts show again - Update scaffold loader coverage to require dismissible persistent banners Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent f129027 commit 3e02f91

5 files changed

Lines changed: 69 additions & 7 deletions

File tree

plugins/power-pages/scripts/tests/create-site-scaffold-loader.test.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,17 @@ const loaderTemplates = [
1111
'astro/src/pages/index.astro',
1212
];
1313

14-
test('create-site loader keeps awaiting-input banner persistent across templates', () => {
14+
test('create-site loader keeps awaiting-input banner persistent and dismissible across templates', () => {
1515
for (const template of loaderTemplates) {
1616
const content = fs.readFileSync(path.join(createSiteRoot, template), 'utf8');
1717

18-
assert.match(content, /if \(banner\) banner\.hidden = !awaiting/, template);
18+
assert.match(content, /id="inputBannerClose"/, template);
19+
assert.match(content, /input-banner-close/, template);
20+
assert.match(content, /aria-label="Dismiss notification"/, template);
21+
assert.match(content, /dismissedPrompt/, template);
22+
assert.match(content, /addEventListener\('click', dismissInputBanner\)/, template);
23+
assert.match(content, /if \(banner\) banner\.hidden = !awaiting \|\| dismissedPrompt === prompt/, template);
24+
assert.match(content, /if \(!awaiting\) dismissedPrompt = null/, template);
1925
assert.match(content, /if \(!lastAwaiting\)/, template);
20-
assert.doesNotMatch(content, /inputBannerClose|input-banner-close|userDismissed|dismissedPrompt/, template);
2126
}
2227
});

plugins/power-pages/skills/create-site/assets/angular/src/app/pages/home.component.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ html, body { overflow: hidden; background: var(--pp-bg); color: var(--pp-text);
116116
.input-banner-text { line-height: 1.4; flex: 1; min-width: 0; }
117117
.input-banner-text b { font-weight: 600; display: block; letter-spacing: 0.3px; }
118118
.input-banner-text small { display: block; font-size: 12px; font-weight: 400; opacity: 0.8; margin-top: 2px; }
119+
.input-banner-close { width: 24px; height: 24px; border: none; border-radius: 50%; background: rgba(92, 61, 0, 0.12); color: #5C3D00; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px; line-height: 1; flex-shrink: 0; transition: background 0.2s ease, transform 0.2s ease; }
120+
.input-banner-close:hover { background: rgba(92, 61, 0, 0.2); transform: scale(1.05); }
119121
@keyframes bannerPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.2); } }
120122
@keyframes bannerEnter { from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: translateY(0); } }
121123
@media (max-width: 600px) { .main-heading { font-size: 24px; } .progress-container { width: 260px; } .feature-cards { flex-direction: column; align-items: center; } .orbit-system { width: 180px; height: 180px; } .input-banner { top: 12px; right: 12px; padding: 10px 12px 10px 16px; font-size: 13px; max-width: calc(100vw - 24px); } }
@@ -134,6 +136,7 @@ html, body { overflow: hidden; background: var(--pp-bg); color: var(--pp-text);
134136
<b>Waiting for your input</b>
135137
<small id="inputBannerPrompt">Please check your terminal to respond.</small>
136138
</div>
139+
<button type="button" class="input-banner-close" id="inputBannerClose" aria-label="Dismiss notification">&times;</button>
137140
</div>
138141
139142
<div class="center-stage" id="centerStage">
@@ -189,13 +192,15 @@ html, body { overflow: hidden; background: var(--pp-bg); color: var(--pp-text);
189192
export class HomeComponent implements AfterViewInit, OnDestroy {
190193
private intervals: number[] = []
191194
private timeouts: number[] = []
195+
private inputBannerCloseCleanup: (() => void) | null = null
192196

193197
ngAfterViewInit() {
194198
const particlesEl = document.getElementById('particles')
195199
const connectorsEl = document.getElementById('connectors')
196200
const statusArea = document.getElementById('statusArea')
197201
const progressLabel = document.getElementById('progressLabel')
198202
const tipTextEl = document.getElementById('tipText')
203+
const inputBannerClose = document.getElementById('inputBannerClose')
199204

200205
// Particles
201206
const createParticle = () => {
@@ -250,6 +255,15 @@ export class HomeComponent implements AfterViewInit, OnDestroy {
250255
let lastLiveMessage: string | null = null
251256
let lastAwaiting = false
252257
let lastPrompt: string | null = null
258+
let dismissedPrompt: string | null = null
259+
260+
const dismissInputBanner = () => {
261+
const banner = document.getElementById('inputBanner')
262+
dismissedPrompt = lastPrompt || 'Please check your terminal to respond.'
263+
if (banner) banner.hidden = true
264+
}
265+
inputBannerClose?.addEventListener('click', dismissInputBanner)
266+
this.inputBannerCloseCleanup = () => inputBannerClose?.removeEventListener('click', dismissInputBanner)
253267

254268
const renderStatusMessage = (text: string) => {
255269
if (!statusArea) return
@@ -318,12 +332,13 @@ export class HomeComponent implements AfterViewInit, OnDestroy {
318332
const prompt = data.inputPrompt || 'Please check your terminal to respond.'
319333
const awaitingChanged = awaiting !== lastAwaiting
320334
const promptChanged = prompt !== lastPrompt
335+
if (!awaiting) dismissedPrompt = null
321336
if (awaitingChanged || promptChanged) {
322337
lastAwaiting = awaiting
323338
lastPrompt = prompt
324339
if (promptEl) promptEl.textContent = prompt
325340
}
326-
if (banner) banner.hidden = !awaiting
341+
if (banner) banner.hidden = !awaiting || dismissedPrompt === prompt
327342
} catch {
328343
if (liveOverride) {
329344
const phaseIndex = Math.min(Math.floor((currentStatusIndex / statuses.length) * phaseLabels.length), phaseLabels.length - 1)
@@ -376,6 +391,7 @@ export class HomeComponent implements AfterViewInit, OnDestroy {
376391
}
377392

378393
ngOnDestroy() {
394+
this.inputBannerCloseCleanup?.()
379395
this.intervals.forEach(id => clearInterval(id))
380396
this.timeouts.forEach(id => clearTimeout(id))
381397
}

plugins/power-pages/skills/create-site/assets/astro/src/pages/index.astro

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Layout from '../layouts/Layout.astro'
1616
<b>Waiting for your input</b>
1717
<small id="inputBannerPrompt">Please check your terminal to respond.</small>
1818
</div>
19+
<button type="button" class="input-banner-close" id="inputBannerClose" aria-label="Dismiss notification">&times;</button>
1920
</div>
2021

2122
<div class="center-stage" id="centerStage">
@@ -180,6 +181,8 @@ html, body { overflow: hidden; background: var(--pp-bg); color: var(--pp-text);
180181
.input-banner-text { line-height: 1.4; flex: 1; min-width: 0; }
181182
.input-banner-text b { font-weight: 600; display: block; letter-spacing: 0.3px; }
182183
.input-banner-text small { display: block; font-size: 12px; font-weight: 400; opacity: 0.8; margin-top: 2px; }
184+
.input-banner-close { width: 24px; height: 24px; border: none; border-radius: 50%; background: rgba(92, 61, 0, 0.12); color: #5C3D00; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px; line-height: 1; flex-shrink: 0; transition: background 0.2s ease, transform 0.2s ease; }
185+
.input-banner-close:hover { background: rgba(92, 61, 0, 0.2); transform: scale(1.05); }
183186
@keyframes bannerPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.2); } }
184187
@keyframes bannerEnter { from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: translateY(0); } }
185188
@media (max-width: 600px) { .main-heading { font-size: 24px; } .progress-container { width: 260px; } .feature-cards { flex-direction: column; align-items: center; } .orbit-system { width: 180px; height: 180px; } .input-banner { top: 12px; right: 12px; padding: 10px 12px 10px 16px; font-size: 13px; max-width: calc(100vw - 24px); } }
@@ -191,6 +194,7 @@ html, body { overflow: hidden; background: var(--pp-bg); color: var(--pp-text);
191194
const statusArea = document.getElementById('statusArea')
192195
const progressLabel = document.getElementById('progressLabel')
193196
const tipTextEl = document.getElementById('tipText')
197+
const inputBannerClose = document.getElementById('inputBannerClose')
194198

195199
// Particles
196200
function createParticle() {
@@ -245,6 +249,14 @@ html, body { overflow: hidden; background: var(--pp-bg); color: var(--pp-text);
245249
let lastLiveMessage: string | null = null
246250
let lastAwaiting = false
247251
let lastPrompt: string | null = null
252+
let dismissedPrompt: string | null = null
253+
254+
const dismissInputBanner = () => {
255+
const banner = document.getElementById('inputBanner')
256+
dismissedPrompt = lastPrompt || 'Please check your terminal to respond.'
257+
if (banner) banner.hidden = true
258+
}
259+
inputBannerClose?.addEventListener('click', dismissInputBanner)
248260

249261
function renderStatusMessage(text: string) {
250262
if (!statusArea) return
@@ -313,12 +325,13 @@ html, body { overflow: hidden; background: var(--pp-bg); color: var(--pp-text);
313325
const prompt = data.inputPrompt || 'Please check your terminal to respond.'
314326
const awaitingChanged = awaiting !== lastAwaiting
315327
const promptChanged = prompt !== lastPrompt
328+
if (!awaiting) dismissedPrompt = null
316329
if (awaitingChanged || promptChanged) {
317330
lastAwaiting = awaiting
318331
lastPrompt = prompt
319332
if (promptEl) promptEl.textContent = prompt
320333
}
321-
if (banner) banner.hidden = !awaiting
334+
if (banner) banner.hidden = !awaiting || dismissedPrompt === prompt
322335
} catch {
323336
if (liveOverride) {
324337
const phaseIndex = Math.min(Math.floor((currentStatusIndex / statuses.length) * phaseLabels.length), phaseLabels.length - 1)

plugins/power-pages/skills/create-site/assets/react/src/pages/Home.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ html, body { overflow: hidden; background: var(--pp-bg); color: var(--pp-text);
112112
.input-banner-text { line-height: 1.4; flex: 1; min-width: 0; }
113113
.input-banner-text b { font-weight: 600; display: block; letter-spacing: 0.3px; }
114114
.input-banner-text small { display: block; font-size: 12px; font-weight: 400; opacity: 0.8; margin-top: 2px; }
115+
.input-banner-close { width: 24px; height: 24px; border: none; border-radius: 50%; background: rgba(92, 61, 0, 0.12); color: #5C3D00; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px; line-height: 1; flex-shrink: 0; transition: background 0.2s ease, transform 0.2s ease; }
116+
.input-banner-close:hover { background: rgba(92, 61, 0, 0.2); transform: scale(1.05); }
115117
@keyframes bannerPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.2); } }
116118
@keyframes bannerEnter { from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: translateY(0); } }
117119
@media (max-width: 600px) { .main-heading { font-size: 24px; } .progress-container { width: 260px; } .feature-cards { flex-direction: column; align-items: center; } .orbit-system { width: 180px; height: 180px; } .input-banner { top: 12px; right: 12px; padding: 10px 12px 10px 16px; font-size: 13px; max-width: calc(100vw - 24px); } }
@@ -127,6 +129,7 @@ export default function Home() {
127129
const statusArea = document.getElementById('statusArea')
128130
const progressLabel = document.getElementById('progressLabel')
129131
const tipTextEl = document.getElementById('tipText')
132+
const inputBannerClose = document.getElementById('inputBannerClose')
130133

131134
// Particles
132135
function createParticle() {
@@ -181,6 +184,14 @@ export default function Home() {
181184
let lastLiveMessage: string | null = null
182185
let lastAwaiting = false
183186
let lastPrompt: string | null = null
187+
let dismissedPrompt: string | null = null
188+
189+
const dismissInputBanner = () => {
190+
const banner = document.getElementById('inputBanner')
191+
dismissedPrompt = lastPrompt || 'Please check your terminal to respond.'
192+
if (banner) banner.hidden = true
193+
}
194+
inputBannerClose?.addEventListener('click', dismissInputBanner)
184195

185196
function renderStatusMessage(text: string) {
186197
if (!statusArea) return
@@ -249,12 +260,13 @@ export default function Home() {
249260
const prompt = data.inputPrompt || 'Please check your terminal to respond.'
250261
const awaitingChanged = awaiting !== lastAwaiting
251262
const promptChanged = prompt !== lastPrompt
263+
if (!awaiting) dismissedPrompt = null
252264
if (awaitingChanged || promptChanged) {
253265
lastAwaiting = awaiting
254266
lastPrompt = prompt
255267
if (promptEl) promptEl.textContent = prompt
256268
}
257-
if (banner) banner.hidden = !awaiting
269+
if (banner) banner.hidden = !awaiting || dismissedPrompt === prompt
258270
} catch {
259271
if (liveOverride) {
260272
const phaseIndex = Math.min(Math.floor((currentStatusIndex / statuses.length) * phaseLabels.length), phaseLabels.length - 1)
@@ -306,6 +318,7 @@ export default function Home() {
306318
intervals.push(window.setInterval(showTip, 12000))
307319

308320
return () => {
321+
inputBannerClose?.removeEventListener('click', dismissInputBanner)
309322
intervals.forEach(id => clearInterval(id))
310323
timeouts.forEach(id => clearTimeout(id))
311324
}
@@ -327,6 +340,7 @@ export default function Home() {
327340
<b>Waiting for your input</b>
328341
<small id="inputBannerPrompt">Please check your terminal to respond.</small>
329342
</div>
343+
<button type="button" className="input-banner-close" id="inputBannerClose" aria-label="Dismiss notification">{'\u00d7'}</button>
330344
</div>
331345

332346
<div className="center-stage" id="centerStage">

plugins/power-pages/skills/create-site/assets/vue/src/pages/Home.vue

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<b>Waiting for your input</b>
1313
<small id="inputBannerPrompt">Please check your terminal to respond.</small>
1414
</div>
15+
<button type="button" class="input-banner-close" id="inputBannerClose" aria-label="Dismiss notification">&times;</button>
1516
</div>
1617

1718
<div class="center-stage" id="centerStage">
@@ -78,6 +79,7 @@ onMounted(() => {
7879
const statusArea = document.getElementById('statusArea')
7980
const progressLabel = document.getElementById('progressLabel')
8081
const tipTextEl = document.getElementById('tipText')
82+
const inputBannerClose = document.getElementById('inputBannerClose')
8183
8284
// Particles
8385
function createParticle() {
@@ -132,6 +134,14 @@ onMounted(() => {
132134
let lastLiveMessage: string | null = null
133135
let lastAwaiting = false
134136
let lastPrompt: string | null = null
137+
let dismissedPrompt: string | null = null
138+
139+
const dismissInputBanner = () => {
140+
const banner = document.getElementById('inputBanner')
141+
dismissedPrompt = lastPrompt || 'Please check your terminal to respond.'
142+
if (banner) banner.hidden = true
143+
}
144+
inputBannerClose?.addEventListener('click', dismissInputBanner)
135145
136146
function renderStatusMessage(text: string) {
137147
if (!statusArea) return
@@ -200,12 +210,13 @@ onMounted(() => {
200210
const prompt = data.inputPrompt || 'Please check your terminal to respond.'
201211
const awaitingChanged = awaiting !== lastAwaiting
202212
const promptChanged = prompt !== lastPrompt
213+
if (!awaiting) dismissedPrompt = null
203214
if (awaitingChanged || promptChanged) {
204215
lastAwaiting = awaiting
205216
lastPrompt = prompt
206217
if (promptEl) promptEl.textContent = prompt
207218
}
208-
if (banner) banner.hidden = !awaiting
219+
if (banner) banner.hidden = !awaiting || dismissedPrompt === prompt
209220
} catch {
210221
if (liveOverride) {
211222
const phaseIndex = Math.min(Math.floor((currentStatusIndex / statuses.length) * phaseLabels.length), phaseLabels.length - 1)
@@ -257,6 +268,7 @@ onMounted(() => {
257268
intervals.push(window.setInterval(showTip, 12000))
258269
259270
cleanupFn = () => {
271+
inputBannerClose?.removeEventListener('click', dismissInputBanner)
260272
intervals.forEach(id => clearInterval(id))
261273
timeouts.forEach(id => clearTimeout(id))
262274
}
@@ -379,6 +391,8 @@ html, body { overflow: hidden; background: var(--pp-bg); color: var(--pp-text);
379391
.input-banner-text { line-height: 1.4; flex: 1; min-width: 0; }
380392
.input-banner-text b { font-weight: 600; display: block; letter-spacing: 0.3px; }
381393
.input-banner-text small { display: block; font-size: 12px; font-weight: 400; opacity: 0.8; margin-top: 2px; }
394+
.input-banner-close { width: 24px; height: 24px; border: none; border-radius: 50%; background: rgba(92, 61, 0, 0.12); color: #5C3D00; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px; line-height: 1; flex-shrink: 0; transition: background 0.2s ease, transform 0.2s ease; }
395+
.input-banner-close:hover { background: rgba(92, 61, 0, 0.2); transform: scale(1.05); }
382396
@keyframes bannerPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.2); } }
383397
@keyframes bannerEnter { from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: translateY(0); } }
384398
@media (max-width: 600px) { .main-heading { font-size: 24px; } .progress-container { width: 260px; } .feature-cards { flex-direction: column; align-items: center; } .orbit-system { width: 180px; height: 180px; } .input-banner { top: 12px; right: 12px; padding: 10px 12px 10px 16px; font-size: 13px; max-width: calc(100vw - 24px); } }

0 commit comments

Comments
 (0)