diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile new file mode 100644 index 0000000..2b6a98e --- /dev/null +++ b/apps/web/Dockerfile @@ -0,0 +1,39 @@ +# Dockerfile for Synor Web Wallet +# Multi-stage build for optimized production image + +# Stage 1: Build +FROM node:20-alpine AS builder + +WORKDIR /app + +# Install dependencies +COPY package.json ./ +RUN npm install + +# Copy source and build +COPY . . +RUN npm run build + +# Stage 2: Serve with nginx +FROM nginx:alpine AS production + +# Copy build output +COPY --from=builder /app/dist /usr/share/nginx/html + +# Copy custom nginx config for SPA routing +RUN echo 'server { \ + listen 80; \ + root /usr/share/nginx/html; \ + index index.html; \ + location / { \ + try_files $uri $uri/ /index.html; \ + } \ + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { \ + expires 1y; \ + add_header Cache-Control "public, immutable"; \ + } \ +}' > /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/apps/web/package.json b/apps/web/package.json index 6bd271b..50be6bd 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -17,7 +17,9 @@ "@noble/hashes": "^1.3.3", "@noble/ed25519": "^2.1.0", "bip39": "^3.1.0", - "zustand": "^4.5.0" + "zustand": "^4.5.0", + "qrcode.react": "^3.1.0", + "html5-qrcode": "^2.3.8" }, "devDependencies": { "@types/react": "^18.3.0", diff --git a/apps/web/src/components/QRCode.tsx b/apps/web/src/components/QRCode.tsx new file mode 100644 index 0000000..2310fd1 --- /dev/null +++ b/apps/web/src/components/QRCode.tsx @@ -0,0 +1,100 @@ +import { QRCodeSVG } from 'qrcode.react'; + +interface QRCodeProps { + value: string; + size?: number; + includeMargin?: boolean; + level?: 'L' | 'M' | 'Q' | 'H'; + className?: string; +} + +/** + * QR Code display component using SVG rendering. + * + * For Synor wallet addresses, the QR code encodes the full address + * in the format: synor: + * + * Error correction levels: + * - L: ~7% recovery + * - M: ~15% recovery (default) + * - Q: ~25% recovery + * - H: ~30% recovery (recommended for addresses) + */ +export function QRCode({ + value, + size = 200, + includeMargin = true, + level = 'H', + className = '', +}: QRCodeProps) { + return ( +
+ +
+ ); +} + +/** + * Generate a Synor payment URI for QR codes. + * Format: synor:
?amount=&label=