feat: add Docker and Nginx configuration, update favicon and icons, enhance image handling in views
12
docker-compose.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
photobooth:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: photobooth
|
||||||
|
volumes:
|
||||||
|
- ./dist:/usr/share/nginx/html
|
||||||
|
- ./nginx.conf:/etc/nginx/conf.d/default.conf
|
||||||
|
ports:
|
||||||
|
- '8080:80'
|
||||||
|
restart: unless-stopped
|
||||||
51
nginx.conf
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# Enable gzip compression
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
gzip_types
|
||||||
|
text/plain
|
||||||
|
text/css
|
||||||
|
text/xml
|
||||||
|
text/javascript
|
||||||
|
application/javascript
|
||||||
|
application/xml+rss
|
||||||
|
application/json;
|
||||||
|
|
||||||
|
# Handle static assets with caching
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
try_files $uri =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle service worker
|
||||||
|
location /sw.js {
|
||||||
|
add_header Cache-Control "no-cache";
|
||||||
|
try_files $uri =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle manifest
|
||||||
|
location /manifest.webmanifest {
|
||||||
|
add_header Content-Type "application/manifest+json";
|
||||||
|
try_files $uri =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle all other routes - fallback to index.html for SPA routing
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||||
|
add_header Pragma "no-cache";
|
||||||
|
add_header Expires "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
}
|
||||||
BIN
public/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 983 B |
BIN
public/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 15 KiB |
BIN
public/icon-192x192.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
@@ -1,4 +0,0 @@
|
|||||||
<svg width="192" height="192" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<rect width="192" height="192" fill="#667eea" rx="24"/>
|
|
||||||
<text x="96" y="120" font-family="Arial" font-size="72" fill="white" text-anchor="middle">📷</text>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 234 B |
BIN
public/icon-512x512.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
@@ -312,7 +312,7 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="final-image-display">
|
<div class="final-image-display">
|
||||||
<img :src="finalImage" alt="Final Combined Image" />
|
<img v-if="finalImage" :src="finalImage" alt="Final Combined Image" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -67,9 +67,9 @@ const applyFilmEffect = (context: CanvasRenderingContext2D, width: number, heigh
|
|||||||
const grainStrength = volume * 1.5;
|
const grainStrength = volume * 1.5;
|
||||||
|
|
||||||
for (let i = 0; i < data.length; i += 4) {
|
for (let i = 0; i < data.length; i += 4) {
|
||||||
let r = data[i];
|
let r = data[i]!;
|
||||||
let g = data[i + 1];
|
let g = data[i + 1]!;
|
||||||
let b = data[i + 2];
|
let b = data[i + 2]!;
|
||||||
|
|
||||||
// --- STEP 1: Apply Contrast (ทำให้ภาพไม่แบน) ---
|
// --- STEP 1: Apply Contrast (ทำให้ภาพไม่แบน) ---
|
||||||
// สูตร Contrast มาตรฐาน
|
// สูตร Contrast มาตรฐาน
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ const applyFilmEffect = (context: CanvasRenderingContext2D, width: number, heigh
|
|||||||
const grainStrength = volume * 1.5;
|
const grainStrength = volume * 1.5;
|
||||||
|
|
||||||
for (let i = 0; i < data.length; i += 4) {
|
for (let i = 0; i < data.length; i += 4) {
|
||||||
let r = data[i];
|
let r = data[i]!;
|
||||||
let g = data[i + 1];
|
let g = data[i + 1]!;
|
||||||
let b = data[i + 2];
|
let b = data[i + 2]!;
|
||||||
|
|
||||||
// --- STEP 1: Apply Contrast (ทำให้ภาพไม่แบน) ---
|
// --- STEP 1: Apply Contrast (ทำให้ภาพไม่แบน) ---
|
||||||
// สูตร Contrast มาตรฐาน
|
// สูตร Contrast มาตรฐาน
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default defineConfig({
|
|||||||
VitePWA({
|
VitePWA({
|
||||||
registerType: 'autoUpdate',
|
registerType: 'autoUpdate',
|
||||||
manifest: {
|
manifest: {
|
||||||
name: 'DekThai Photobooth',
|
name: 'Photobooth-APU',
|
||||||
short_name: 'Photobooth',
|
short_name: 'Photobooth',
|
||||||
description: 'Create beautiful photo strips with frames',
|
description: 'Create beautiful photo strips with frames',
|
||||||
theme_color: '#ffffff',
|
theme_color: '#ffffff',
|
||||||
|
|||||||