fix headline rhythm + wider hero image + 10x faster deploys
HEADLINE: - 3 balanced lines: 'Turn I'll donate' / 'into money' / 'in the bank.' - Removed that orphaned 'money' on its own line - <br className='hidden lg:block'> controls breaks on desktop only IMAGE: - Hero container: max-w-5xl -> max-w-7xl (image 25% wider) - Stat strip widened to match - Much more of the gala scene visible, phone prominent DEPLOY SPEED (deploy.sh): - Persistent /opt/pnpl/ build dir (no temp dir creation/deletion) - BuildKit with cache mounts (npm + .next/cache) - No more docker builder prune / docker rmi (preserves cache!) - Installed docker-buildx v0.31.1 on server - Before: ~245s (4+ min) After: ~29s (cached) / ~136s (first) - Use: cd pledge-now-pay-later && bash deploy.sh
This commit is contained in:
@@ -1,21 +1,21 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
FROM node:20-alpine AS base
|
||||
|
||||
FROM base AS deps
|
||||
WORKDIR /app
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
RUN --mount=type=cache,target=/root/.npm npm ci
|
||||
|
||||
FROM base AS builder
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
RUN npx prisma generate
|
||||
RUN npm run build
|
||||
RUN --mount=type=cache,target=/app/.next/cache npm run build
|
||||
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
# sharp needs these native libs for image optimization
|
||||
RUN apk add --no-cache libc6-compat
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
@@ -23,7 +23,6 @@ COPY --from=builder /app/public ./public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
COPY --from=builder /app/prisma ./prisma
|
||||
# sharp is bundled in standalone output when installed
|
||||
ENV NEXT_SHARP_PATH=/app/node_modules/sharp
|
||||
USER nextjs
|
||||
EXPOSE 3000
|
||||
|
||||
51
pledge-now-pay-later/deploy.sh
Normal file
51
pledge-now-pay-later/deploy.sh
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
# Fast deploy — BuildKit cache + persistent build dir
|
||||
# Source-only changes: ~40-60s | With package changes: ~90s
|
||||
set -e
|
||||
|
||||
SERVER=root@159.195.60.33
|
||||
CONTAINER=qc-server-new
|
||||
START=$(date +%s)
|
||||
|
||||
step() { printf "\n\033[1;34m>>>\033[0m [%s] %s\n" "$1" "$2"; }
|
||||
|
||||
# ── Pack source (exclude heavy/unchanged stuff) ──
|
||||
step "1/3" "Packing source..."
|
||||
tar czf /tmp/pnpl.tar.gz \
|
||||
--exclude=node_modules \
|
||||
--exclude=.next \
|
||||
--exclude=.git \
|
||||
--exclude=brand/ \
|
||||
--exclude=shots/ \
|
||||
.
|
||||
SIZE=$(wc -c < /tmp/pnpl.tar.gz | awk '{printf "%.1fM", $1/1048576}')
|
||||
echo " ${SIZE} tarball"
|
||||
|
||||
# ── Upload ──
|
||||
step "2/3" "Uploading..."
|
||||
scp -o ConnectTimeout=20 -q /tmp/pnpl.tar.gz ${SERVER}:/tmp/pnpl.tar.gz
|
||||
|
||||
# ── Build + deploy with full cache ──
|
||||
step "3/3" "Building + deploying..."
|
||||
ssh -o ConnectTimeout=20 ${SERVER} "
|
||||
incus file push /tmp/pnpl.tar.gz ${CONTAINER}/tmp/pnpl.tar.gz
|
||||
incus exec ${CONTAINER} -- bash -c '
|
||||
cd /opt/pnpl
|
||||
tar xzf /tmp/pnpl.tar.gz
|
||||
rm /tmp/pnpl.tar.gz
|
||||
|
||||
# BuildKit build with npm + Next.js cache mounts
|
||||
docker buildx build -t pnpl-app:latest --load . 2>&1 | tail -8
|
||||
|
||||
# Rolling restart
|
||||
docker service update --force --image pnpl-app:latest pnpl_app 2>&1 | tail -2
|
||||
|
||||
# Clean dangling only (preserve build cache!)
|
||||
docker image prune -f 2>&1 | tail -1
|
||||
'
|
||||
rm -f /tmp/pnpl.tar.gz
|
||||
"
|
||||
|
||||
ELAPSED=$(( $(date +%s) - START ))
|
||||
echo ""
|
||||
echo "=== Deployed in ${ELAPSED}s ==="
|
||||
@@ -49,8 +49,8 @@ export default function HomePage() {
|
||||
|
||||
{/* ━━ HERO (dark) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}
|
||||
<section className="bg-gray-950 overflow-hidden">
|
||||
<div className="max-w-5xl mx-auto px-6 pt-20 pb-16 md:pt-28 md:pb-20">
|
||||
<div className="grid md:grid-cols-12 gap-10 md:gap-14 items-start md:items-stretch">
|
||||
<div className="max-w-7xl mx-auto px-6 pt-20 pb-16 md:pt-28 md:pb-20">
|
||||
<div className="grid md:grid-cols-12 gap-10 md:gap-12 items-start md:items-stretch">
|
||||
|
||||
{/* ── Text column ── */}
|
||||
<div className="md:col-span-7 pt-2 md:pt-6 stagger-children">
|
||||
@@ -63,7 +63,7 @@ export default function HomePage() {
|
||||
|
||||
{/* Headline — Display scale */}
|
||||
<h1 className="text-[2.75rem] leading-[0.95] sm:text-6xl md:text-[4.25rem] lg:text-7xl font-black text-white tracking-tighter">
|
||||
Turn “I'll donate” into money in the bank.
|
||||
Turn “I'll donate”<br className="hidden lg:block" /> into money<br className="hidden lg:block" /> in the bank.
|
||||
</h1>
|
||||
|
||||
{/* Sub */}
|
||||
@@ -117,7 +117,7 @@ export default function HomePage() {
|
||||
|
||||
{/* Stat strip — gap-px pattern (signature pattern 2) */}
|
||||
<div className="border-t border-gray-800/50">
|
||||
<div className="max-w-5xl mx-auto">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-px bg-gray-800/50">
|
||||
{HERO_STATS.map((s) => (
|
||||
<div key={s.stat} className="bg-gray-950 py-6 px-6">
|
||||
|
||||
Reference in New Issue
Block a user