fix(qr-button): improve layout and z-index

- Stack room code and share link vertically on left
- Place square QR button on right, spanning both rows
- Show mini QR code (40px) in button instead of emoji
- Fix popover z-index to appear above dropdown menu (z: 10000)
- Reduce button padding for more compact appearance

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-10-23 10:30:47 -05:00
parent 349290ac6a
commit 646a4228d0
7 changed files with 732 additions and 527 deletions

16
.mcp.json Normal file
View File

@ -0,0 +1,16 @@
{
"mcpServers": {
"sqlite": {
"command": "/Users/antialias/.nvm/versions/node/v20.19.3/bin/npx",
"args": [
"-y",
"mcp-server-sqlite-npx",
"/Users/antialias/projects/soroban-abacus-flashcards/apps/web/data/sqlite.db"
],
"env": {
"PATH": "/Users/antialias/.nvm/versions/node/v20.19.3/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin",
"NODE_PATH": "/Users/antialias/.nvm/versions/node/v20.19.3/lib/node_modules"
}
}
}
}

View File

@ -267,3 +267,20 @@ Before setting a z-index, always check:
1. What stacking context is this element in? 1. What stacking context is this element in?
2. Am I comparing against siblings or global elements? 2. Am I comparing against siblings or global elements?
3. Does my parent create a stacking context? 3. Does my parent create a stacking context?
## Database Access
This project uses SQLite with Drizzle ORM. Database location: `./data/sqlite.db`
**ALWAYS use MCP SQLite tools for database operations:**
- `mcp__sqlite__list_tables` - List all tables
- `mcp__sqlite__describe_table` - Get table schema
- `mcp__sqlite__read_query` - Run SELECT queries
- `mcp__sqlite__write_query` - Run INSERT/UPDATE/DELETE queries
- `mcp__sqlite__create_table` - Create new tables
- **DO NOT use bash `sqlite3` commands** - use the MCP tools instead
**Database Schema:**
- Schema definitions: `src/db/schema/`
- Drizzle config: `drizzle.config.ts`
- Migrations: `drizzle/` directory

View File

@ -104,9 +104,17 @@
"Bash(do gh run list --limit 1 --workflow=\"Build and Deploy\" --json conclusion,status,databaseId --jq '.[0] | \"\"\\(.status) - \\(.conclusion // \"\"running\"\") - Run \\(.databaseId)\"\"')", "Bash(do gh run list --limit 1 --workflow=\"Build and Deploy\" --json conclusion,status,databaseId --jq '.[0] | \"\"\\(.status) - \\(.conclusion // \"\"running\"\") - Run \\(.databaseId)\"\"')",
"Bash(do ssh nas.home.network '/usr/local/bin/docker inspect soroban-abacus-flashcards --format=\"\"{{index .Config.Labels \\\"\"org.opencontainers.image.revision\\\"\"}}\"\"')", "Bash(do ssh nas.home.network '/usr/local/bin/docker inspect soroban-abacus-flashcards --format=\"\"{{index .Config.Labels \\\"\"org.opencontainers.image.revision\\\"\"}}\"\"')",
"Bash(git rev-parse HEAD)", "Bash(git rev-parse HEAD)",
"Bash(gh run watch --exit-status 18662351595)" "Bash(gh run watch --exit-status 18662351595)",
"WebFetch(domain:github.com)",
"WebSearch",
"WebFetch(domain:www.npmjs.com)",
"mcp__sqlite__list_tables",
"mcp__sqlite__describe_table",
"mcp__sqlite__read_query"
], ],
"deny": [], "deny": [],
"ask": [] "ask": []
} },
"enableAllProjectMcpServers": true,
"enabledMcpjsonServers": ["sqlite"]
} }

View File

@ -3,6 +3,7 @@ import type { CSSProperties } from 'react'
import { useState } from 'react' import { useState } from 'react'
import { QRCodeSVG } from 'qrcode.react' import { QRCodeSVG } from 'qrcode.react'
import { useClipboard } from '@/hooks/useClipboard' import { useClipboard } from '@/hooks/useClipboard'
import { Z_INDEX } from '@/constants/zIndex'
export interface QRCodeButtonProps { export interface QRCodeButtonProps {
/** /**
@ -25,21 +26,20 @@ export function QRCodeButton({ url, style }: QRCodeButtonProps) {
const { copied, copy } = useClipboard() const { copied, copy } = useClipboard()
const buttonStyles: CSSProperties = { const buttonStyles: CSSProperties = {
width: '100%',
cursor: 'pointer', cursor: 'pointer',
transition: 'all 0.2s ease', transition: 'all 0.2s ease',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
gap: '8px',
marginBottom: '6px',
border: '2px solid rgba(251, 146, 60, 0.4)', border: '2px solid rgba(251, 146, 60, 0.4)',
background: 'linear-gradient(135deg, rgba(251, 146, 60, 0.2), rgba(251, 146, 60, 0.3))', background: 'linear-gradient(135deg, rgba(251, 146, 60, 0.2), rgba(251, 146, 60, 0.3))',
borderRadius: '8px', borderRadius: '8px',
padding: '10px 16px', padding: '6px',
fontSize: '13px', fontSize: '16px',
fontWeight: '600',
color: 'rgba(253, 186, 116, 1)', color: 'rgba(253, 186, 116, 1)',
aspectRatio: '1',
alignSelf: 'stretch',
flexShrink: 0,
...style, ...style,
} }
@ -61,8 +61,7 @@ export function QRCodeButton({ url, style }: QRCodeButtonProps) {
Object.assign(e.currentTarget.style, buttonStyles) Object.assign(e.currentTarget.style, buttonStyles)
}} }}
> >
<span style={{ fontSize: '16px' }}>📱</span> <QRCodeSVG value={url} size={40} level="L" />
<span>QR Code</span>
</button> </button>
</Popover.Trigger> </Popover.Trigger>
@ -77,7 +76,7 @@ export function QRCodeButton({ url, style }: QRCodeButtonProps) {
borderRadius: '12px', borderRadius: '12px',
padding: '20px', padding: '20px',
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.4)', boxShadow: '0 8px 32px rgba(0, 0, 0, 0.4)',
zIndex: 1000, zIndex: Z_INDEX.GAME_NAV.HAMBURGER_NESTED_DROPDOWN,
maxWidth: '320px', maxWidth: '320px',
}} }}
> >

File diff suppressed because it is too large Load Diff

View File

@ -19,31 +19,37 @@ export interface RoomShareButtonsProps {
*/ */
export function RoomShareButtons({ joinCode, shareUrl }: RoomShareButtonsProps) { export function RoomShareButtons({ joinCode, shareUrl }: RoomShareButtonsProps) {
return ( return (
<> <div style={{ display: 'flex', gap: '6px', marginBottom: '6px' }}>
<CopyButton {/* Left side: stacked buttons */}
text={joinCode} <div style={{ display: 'flex', flexDirection: 'column', gap: '6px', flex: 1 }}>
variant="code" <CopyButton
label={ text={joinCode}
<> variant="code"
<span>📋</span> label={
<span>{joinCode}</span> <>
</> <span>📋</span>
} <span>{joinCode}</span>
/> </>
}
style={{ marginBottom: 0 }}
/>
<CopyButton <CopyButton
text={shareUrl} text={shareUrl}
variant="link" variant="link"
label={ label={
<> <>
<span>🔗</span> <span>🔗</span>
<span>Share Link</span> <span>Share Link</span>
</> </>
} }
copiedLabel="Link Copied!" copiedLabel="Link Copied!"
/> style={{ marginBottom: 0 }}
/>
</div>
{/* Right side: QR code button */}
<QRCodeButton url={shareUrl} /> <QRCodeButton url={shareUrl} />
</> </div>
) )
} }

View File

@ -173,6 +173,9 @@ importers:
python-bridge: python-bridge:
specifier: ^1.1.0 specifier: ^1.1.0
version: 1.1.0 version: 1.1.0
qrcode.react:
specifier: ^4.2.0
version: 4.2.0(react@18.3.1)
react: react:
specifier: ^18.2.0 specifier: ^18.2.0
version: 18.3.1 version: 18.3.1
@ -7726,6 +7729,11 @@ packages:
python-bridge@1.1.0: python-bridge@1.1.0:
resolution: {integrity: sha512-qjQ0QB8p9cn/XDeILQH0aP307hV58lrmv0Opjyub68Um7FHdF+ZXlTqyxNkKaXOFk2QSkScoPWwn7U9GGnrkeQ==} resolution: {integrity: sha512-qjQ0QB8p9cn/XDeILQH0aP307hV58lrmv0Opjyub68Um7FHdF+ZXlTqyxNkKaXOFk2QSkScoPWwn7U9GGnrkeQ==}
qrcode.react@4.2.0:
resolution: {integrity: sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
qs@6.13.0: qs@6.13.0:
resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}
engines: {node: '>=0.6'} engines: {node: '>=0.6'}
@ -17587,6 +17595,10 @@ snapshots:
dependencies: dependencies:
bluebird: 3.7.2 bluebird: 3.7.2
qrcode.react@4.2.0(react@18.3.1):
dependencies:
react: 18.3.1
qs@6.13.0: qs@6.13.0:
dependencies: dependencies:
side-channel: 1.1.0 side-channel: 1.1.0