Reubencf commited on
Commit
4632852
Β·
1 Parent(s): 26cefad

Fix Dockerfile and ensure package-lock.json is present for Hugging Face Spaces deployment

Browse files
Files changed (2) hide show
  1. Dockerfile +14 -18
  2. components/HuggingFaceQRGenerator.tsx +12 -12
Dockerfile CHANGED
@@ -1,5 +1,4 @@
1
- # Use Node.js 20 Alpine as base image
2
- FROM node:20-alpine AS base
3
 
4
  # Install dependencies only when needed
5
  FROM base AS deps
@@ -8,9 +7,8 @@ RUN apk add --no-cache libc6-compat
8
  WORKDIR /app
9
 
10
  # Install dependencies based on the preferred package manager
11
- COPY package.json package-lock.json* ./
12
- RUN npm ci --only=production && \
13
- npm ci --only=development
14
 
15
  # Rebuild the source code only when needed
16
  FROM base AS builder
@@ -21,9 +19,8 @@ COPY . .
21
  # Next.js collects completely anonymous telemetry data about general usage.
22
  # Learn more here: https://nextjs.org/telemetry
23
  # Uncomment the following line in case you want to disable telemetry during the build.
24
- ENV NEXT_TELEMETRY_DISABLED 1
25
 
26
- # Build the Next.js application
27
  RUN npm run build
28
 
29
  # Production image, copy all the files and run next
@@ -32,30 +29,29 @@ WORKDIR /app
32
 
33
  ENV NODE_ENV production
34
  # Uncomment the following line in case you want to disable telemetry during runtime.
35
- ENV NEXT_TELEMETRY_DISABLED 1
36
 
37
- # Create a non-root user
38
  RUN addgroup --system --gid 1001 nodejs
39
  RUN adduser --system --uid 1001 nextjs
40
 
41
- # Copy built application
42
  COPY --from=builder /app/public ./public
43
- COPY --from=builder /app/.next/standalone ./
44
- COPY --from=builder /app/.next/static ./.next/static
45
 
46
  # Set the correct permission for prerender cache
47
- RUN mkdir -p .next
48
  RUN chown nextjs:nodejs .next
49
 
50
- # Switch to the non-root user
 
 
 
 
51
  USER nextjs
52
 
53
- # Expose port 7860 (Hugging Face Spaces default)
54
  EXPOSE 7860
55
 
56
- # Set environment variable for the port
57
  ENV PORT 7860
58
  ENV HOSTNAME "0.0.0.0"
59
 
60
- # Start the application
61
- CMD ["node", "server.js"]
 
 
1
+ FROM node:18-alpine AS base
 
2
 
3
  # Install dependencies only when needed
4
  FROM base AS deps
 
7
  WORKDIR /app
8
 
9
  # Install dependencies based on the preferred package manager
10
+ COPY package.json package-lock.json ./
11
+ RUN npm ci
 
12
 
13
  # Rebuild the source code only when needed
14
  FROM base AS builder
 
19
  # Next.js collects completely anonymous telemetry data about general usage.
20
  # Learn more here: https://nextjs.org/telemetry
21
  # Uncomment the following line in case you want to disable telemetry during the build.
22
+ # ENV NEXT_TELEMETRY_DISABLED 1
23
 
 
24
  RUN npm run build
25
 
26
  # Production image, copy all the files and run next
 
29
 
30
  ENV NODE_ENV production
31
  # Uncomment the following line in case you want to disable telemetry during runtime.
32
+ # ENV NEXT_TELEMETRY_DISABLED 1
33
 
 
34
  RUN addgroup --system --gid 1001 nodejs
35
  RUN adduser --system --uid 1001 nextjs
36
 
 
37
  COPY --from=builder /app/public ./public
 
 
38
 
39
  # Set the correct permission for prerender cache
40
+ RUN mkdir .next
41
  RUN chown nextjs:nodejs .next
42
 
43
+ # Automatically leverage output traces to reduce image size
44
+ # https://nextjs.org/docs/advanced-features/output-file-tracing
45
+ COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
46
+ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
47
+
48
  USER nextjs
49
 
 
50
  EXPOSE 7860
51
 
 
52
  ENV PORT 7860
53
  ENV HOSTNAME "0.0.0.0"
54
 
55
+ # server.js is created by next build from the standalone output
56
+ # https://nextjs.org/docs/pages/api-reference/next-config-js/output
57
+ CMD ["node", "server.js"]
components/HuggingFaceQRGenerator.tsx CHANGED
@@ -24,17 +24,17 @@ const HuggingFaceQRGenerator = () => {
24
  const [showQR, setShowQR] = useState(false);
25
  const [gradientIndex, setGradientIndex] = useState(0);
26
  const [showColorPicker, setShowColorPicker] = useState(false);
27
- const [customColor, setCustomColor] = useState<string | null>(null);
28
 
29
  const gradients = [
30
- { name: 'Sunset Orange', colors: ['#f1c40f', '#f39c12'], type: 'gradient' },
31
- { name: 'Ocean Blue', colors: ['#60a5fa', '#3b82f6'], type: 'gradient' },
32
- { name: 'Emerald Green', colors: ['#34d399', '#10b981'], type: 'gradient' },
33
- { name: 'Purple Dream', colors: ['#a78bfa', '#7c3aed'], type: 'gradient' },
34
- { name: 'Rose Pink', colors: ['#fb7185', '#f472b6'], type: 'gradient' },
35
- { name: 'Amber Gold', colors: ['#fbbf24', '#f59e0b'], type: 'gradient' },
36
- { name: 'Teal Breeze', colors: ['#2dd4bf', '#14b8a6'], type: 'gradient' },
37
- { name: 'Indigo Night', colors: ['#6366f1', '#4f46e5'], type: 'gradient' },
38
  ];
39
 
40
  const solidColors = [
@@ -140,7 +140,7 @@ const HuggingFaceQRGenerator = () => {
140
  pixelRatio: 2,
141
  width: Math.ceil(rect.width),
142
  height: Math.ceil(rect.height),
143
- style: { margin: '0' }
144
  });
145
  const response = await fetch(dataUrl);
146
  const blob = await response.blob();
@@ -234,7 +234,7 @@ const HuggingFaceQRGenerator = () => {
234
  pixelRatio: 2,
235
  width: Math.ceil(rect.width),
236
  height: Math.ceil(rect.height),
237
- style: { margin: '0' }
238
  });
239
 
240
  // Convert data URL to blob
@@ -362,7 +362,7 @@ const HuggingFaceQRGenerator = () => {
362
  <div className="qr-card-v2" id="qr-card" ref={cardRef} onClick={(e) => e.stopPropagation()}>
363
  <div className="qr-avatar-wrap">
364
  <img
365
- src={profileData.avatarUrl}
366
  alt={profileData.fullName}
367
  className="qr-avatar"
368
  crossOrigin="anonymous"
 
24
  const [showQR, setShowQR] = useState(false);
25
  const [gradientIndex, setGradientIndex] = useState(0);
26
  const [showColorPicker, setShowColorPicker] = useState(false);
27
+ const [customColor, setCustomColor] = useState<string | null>('#f59e0b');
28
 
29
  const gradients = [
30
+ { name: 'Sunset', colors: ['#f59e0b', '#f43f5e'], type: 'gradient' }, // orange β†’ rose
31
+ { name: 'Aqua Blue', colors: ['#06b6d4', '#3b82f6'], type: 'gradient' }, // cyan β†’ blue
32
+ { name: 'Purple Orange', colors: ['#8b5cf6', '#f59e0b'], type: 'gradient' }, // purple β†’ orange
33
+ { name: 'Emerald Gold', colors: ['#10b981', '#fbbf24'], type: 'gradient' }, // green β†’ amber
34
+ { name: 'Indigo Pink', colors: ['#4f46e5', '#ec4899'], type: 'gradient' }, // indigo β†’ pink
35
+ { name: 'Teal Violet', colors: ['#14b8a6', '#7c3aed'], type: 'gradient' }, // teal β†’ violet
36
+ { name: 'Sky Purple', colors: ['#38bdf8', '#a78bfa'], type: 'gradient' }, // sky β†’ purple
37
+ { name: 'Slate Blue', colors: ['#64748b', '#3b82f6'], type: 'gradient' }, // slate β†’ blue
38
  ];
39
 
40
  const solidColors = [
 
140
  pixelRatio: 2,
141
  width: Math.ceil(rect.width),
142
  height: Math.ceil(rect.height),
143
+ style: { margin: '0' },
144
  });
145
  const response = await fetch(dataUrl);
146
  const blob = await response.blob();
 
234
  pixelRatio: 2,
235
  width: Math.ceil(rect.width),
236
  height: Math.ceil(rect.height),
237
+ style: { margin: '0' },
238
  });
239
 
240
  // Convert data URL to blob
 
362
  <div className="qr-card-v2" id="qr-card" ref={cardRef} onClick={(e) => e.stopPropagation()}>
363
  <div className="qr-avatar-wrap">
364
  <img
365
+ src={profileData.originalAvatarUrl || profileData.avatarUrl}
366
  alt={profileData.fullName}
367
  className="qr-avatar"
368
  crossOrigin="anonymous"