Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,40 @@ jobs:
- name: Validate HTML
run: html-validate index.html

# ── Playwright responsive / layout tests ─────────────────────
test:
name: Responsive Layout Tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install dependencies
run: npm ci
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This job uses npm ci, but the repo ignores package-lock.json (see .gitignore:3) and there doesn’t appear to be a lockfile committed. npm ci will fail without a lockfile. Either commit a lockfile (and stop ignoring it) or switch this step to npm install (optionally with a pinned Node + caching) so CI can install Playwright reliably.

Suggested change
run: npm ci
run: npm install

Copilot uses AI. Check for mistakes.

- name: Install Playwright browsers
run: npx playwright install chromium --with-deps

- name: Run Playwright tests
run: npx playwright test --reporter=list

- name: Upload Playwright report on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: playwright-report/
retention-days: 7

# ── Deploy (only on push to main) ────────────────────────────
deploy:
name: Deploy to GitHub Pages
needs: validate
needs: [validate, test]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-latest

Expand Down Expand Up @@ -61,3 +91,4 @@ jobs:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

165 changes: 148 additions & 17 deletions css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@

--chess-panel-padding: 4rem; /* total horizontal padding within chess panel (2 × 1rem + margins) */

/* Board size: fills the 70 % chess panel minus padding, capped at 720 px.
/* Board size: fills the 68 % chess panel minus padding, capped at 720 px.
Also constrained by viewport height (subtracting ~280px for header 56px +
player bars ~80px + controls ~40px + move history ~100px + gaps ~4px). */
--board-sz: clamp(300px, min(calc(70vw - var(--chess-panel-padding) * 2), calc(100vh - 280px)), 720px);
--board-sz: clamp(300px, min(calc(68vw - var(--chess-panel-padding) * 2), calc(100vh - 280px)), 720px);

--text-primary: #e6edf3;
--text-secondary: #8b949e;
Expand Down Expand Up @@ -166,8 +166,8 @@ a { color: var(--accent-blue); }
align-items: center;
padding: 1rem;
gap: .6rem;
flex: 0 0 70%;
width: 70%;
flex: 0 0 68%;
width: 68%;
min-width: 0;
overflow-y: auto;
scrollbar-width: thin;
Expand Down Expand Up @@ -405,22 +405,25 @@ a { color: var(--accent-blue); }

/* ── SQL Panel ──────────────────────────────────────────────── */
.sql-panel {
flex: 0 0 30%;
width: 30%;
flex: 0 0 32%;
width: 32%;
min-width: 300px;
display: flex;
flex-direction: column;
border-left: 1px solid var(--bg-border);
background: var(--sql-bg);
overflow: hidden;
min-width: 0;
transition: width .25s ease, flex .25s ease, opacity .2s;
}
.sql-panel.hidden-panel {
flex: 0 0 0;
width: 0;
/* Override the base min-width (300 px) so the panel collapses fully */
min-width: 0;
opacity: 0;
pointer-events: none;
border-left: none;
overflow: hidden;
}

.sql-panel-header {
Expand Down Expand Up @@ -459,13 +462,16 @@ a { color: var(--accent-blue); }
/* SQL content area */
.sql-content {
flex: 1;
min-height: 0;
overflow-y: auto;
overflow-x: hidden;
padding: .75rem 1rem;
display: flex;
flex-direction: column;
gap: .75rem;
scroll-behavior: smooth;
scrollbar-width: thin;
scrollbar-color: var(--bg-border) transparent;
}

.sql-placeholder {
Expand Down Expand Up @@ -782,7 +788,9 @@ input:checked + .slider::before { transform: translateX(18px); }
font-size: .78rem;
line-height: 1.6;
padding: .6rem .75rem;
resize: none;
resize: vertical;
min-height: 7.5rem;
max-height: 20rem;
outline: none;
transition: background .15s;
}
Expand Down Expand Up @@ -845,41 +853,164 @@ input:checked + .slider::before { transform: translateX(18px); }
.sql-input-section { display: flex; }
}

/* ── Responsive: Tablet (≤ 1024 px) ────────────────────────── */
@media (max-width: 1024px) {
.sql-panel {
flex: 0 0 36%;
width: 36%;
min-width: 260px;
}
.chess-panel {
flex: 0 0 64%;
width: 64%;
}
:root {
--board-sz: clamp(280px,
min(calc(64vw - var(--chess-panel-padding) * 2), calc(100vh - 280px)),
640px);
}
}

/* ── Responsive: Mobile landscape / narrow (≤ 900 px) ──────── */
@media (max-width: 900px) {
.app-main { flex-direction: column; overflow-y: auto; overflow-x: hidden; }
.app-main {
flex-direction: column;
overflow: hidden;
}

.chess-panel {
flex: none;
flex: 0 0 auto;
width: 100%;
max-height: 58vh;
min-height: auto;
overflow-y: visible;
overflow-y: auto;
scrollbar-width: thin;
}

.sql-panel {
flex: none;
flex: 1 1 auto;
width: 100%;
min-width: 0;
min-height: 40vh;
border-left: none;
border-top: 1px solid var(--bg-border);
height: 45vh;
min-height: 260px;
overflow: hidden;
}
.sql-panel.hidden-panel {
height: 0;
flex: 0 0 0;
min-height: 0;
height: 0;
border-top: none;
overflow: hidden;
}

.sql-move-input {
min-height: 5.5rem;
}

/* Mobile: limit by both viewport width and height to handle short screens */
:root { --board-sz: min(90vw, 440px, calc(55vh)); }
}

/* ── Responsive: Mobile portrait (≤ 600 px) ────────────────── */
@media (max-width: 600px) {
.chess-panel {
max-height: 54vh;
padding: .6rem;
}

.sql-panel {
min-height: 44vh;
}

.sql-move-input {
min-height: 5rem;
font-size: .75rem;
}

.sql-panel-header {
padding: .4rem .75rem;
}

.sql-input-bar {
padding: .45rem .75rem;
}

:root { --board-sz: min(90vw, 380px, calc(50vh)); }
}

/* ── Responsive: Small phone (≤ 480 px) ────────────────────── */
@media (max-width: 480px) {
.app-header { padding: 0 .75rem; }
.header-logo .logo-text { display: none; }
.chess-panel { padding: .5rem; }
.chess-panel { padding: .5rem; gap: .4rem; max-height: 52vh; }
.header-controls { gap: .3rem; }

:root { --board-sz: min(92vw, 360px); }
.sql-panel { min-height: 46vh; }

.sql-move-input { min-height: 4.5rem; }

:root { --board-sz: min(92vw, 340px, calc(48vh)); }

#btnToggleSQL #sqlToggleLabel { display: none; }
}

/* ── Responsive: Wide screens (≥ 1440 px) ──────────────────── */
@media (min-width: 1440px) {
.sql-panel {
flex: 0 0 28%;
width: 28%;
min-width: 340px;
}
.chess-panel {
flex: 0 0 72%;
width: 72%;
}
:root {
--board-sz: clamp(400px,
min(calc(72vw - var(--chess-panel-padding) * 2), calc(100vh - 280px)),
760px);
}
}

/* ── Responsive: Very wide screens (≥ 1920 px) ─────────────── */
@media (min-width: 1920px) {
.sql-panel {
flex: 0 0 26%;
width: 26%;
min-width: 400px;
}
.chess-panel {
flex: 0 0 74%;
width: 74%;
}
.sql-move-input {
min-height: 9rem;
}
}

/* ── Responsive: Short landscape (height < 500 px) ─────────── */
/* e.g. phones in landscape orientation */
@media (max-height: 500px) {
.chess-panel {
max-height: 50vh;
}
.sql-panel {
min-height: 48vh;
}
.sql-move-input {
min-height: 3rem;
max-height: 6rem;
}
.sql-input-bar {
min-height: 36px;
padding: .25rem .75rem;
}
.sql-input-actions {
padding: .25rem .5rem;
}
.sql-panel-header {
padding: .35rem .75rem;
}
}

2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ <h2 class="sql-title">
id="sqlMoveInput"
class="sql-move-input"
spellcheck="false"
rows="3"
rows="6"
placeholder="UPDATE chess_piece&#10;SET position = 'e4'&#10;WHERE position = 'e2';&#10;&#10;-- or shorthand: e2 e4"></textarea>
<div class="sql-input-actions">
<span class="sql-run-error hidden" id="sqlRunError"></span>
Expand Down
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
{
"dependencies": {
"chess.js": "^0.10.3"
},
"devDependencies": {
"@playwright/test": "^1.59.1"
},
"scripts": {
"test": "playwright test",
"test:report": "playwright show-report"
}
}
61 changes: 61 additions & 0 deletions playwright.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// @ts-check
const { defineConfig, devices } = require('@playwright/test');
const path = require('path');

module.exports = defineConfig({
testDir: './tests',
timeout: 30_000,
retries: 0,
reporter: [['list'], ['html', { open: 'never' }]],

use: {
/* Serve index.html directly via file:// so no server is needed */
baseURL: 'file://' + path.resolve(__dirname, 'index.html'),
headless: true,
screenshot: 'only-on-failure',
video: 'off',
},
Comment on lines +11 to +17
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use.baseURL is configured here, but the tests use their own PAGE_URL and call page.goto(PAGE_URL) directly, so baseURL is currently unused. Consider either switching tests to page.goto('/') (and drop the per-test PAGE_URL), or removing baseURL from the config to avoid having two sources of truth for the test entrypoint.

Copilot uses AI. Check for mistakes.

projects: [
/* Desktop sizes */
{
name: 'desktop-1920x1080',
use: { ...devices['Desktop Chrome'], viewport: { width: 1920, height: 1080 } },
},
{
name: 'desktop-1440x900',
use: { ...devices['Desktop Chrome'], viewport: { width: 1440, height: 900 } },
},
{
name: 'desktop-1280x800',
use: { ...devices['Desktop Chrome'], viewport: { width: 1280, height: 800 } },
},
/* Tablet sizes */
{
name: 'tablet-1024x768',
use: { ...devices['Desktop Chrome'], viewport: { width: 1024, height: 768 } },
},
{
name: 'tablet-portrait-768x1024',
use: { ...devices['Desktop Chrome'], viewport: { width: 768, height: 1024 } },
},
/* Mobile sizes */
{
name: 'mobile-portrait-390x844',
use: { ...devices['Desktop Chrome'], viewport: { width: 390, height: 844 } },
},
{
name: 'mobile-landscape-844x390',
use: { ...devices['Desktop Chrome'], viewport: { width: 844, height: 390 } },
},
{
name: 'mobile-small-360x640',
use: { ...devices['Desktop Chrome'], viewport: { width: 360, height: 640 } },
},
/* Ultrawide */
{
name: 'ultrawide-2560x1080',
use: { ...devices['Desktop Chrome'], viewport: { width: 2560, height: 1080 } },
},
],
});
4 changes: 4 additions & 0 deletions test-results/.last-run.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"status": "passed",
"failedTests": []
}
Comment on lines +1 to +4
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test-results/.last-run.json is a generated Playwright artifact and will change across runs; committing it will create noisy diffs and potential merge conflicts. It should be removed from version control and the test-results/ directory should be added to .gitignore (similar to playwright-report/).

Suggested change
{
"status": "passed",
"failedTests": []
}

Copilot uses AI. Check for mistakes.
Loading
Loading