From 9dc66b02fa078289a0c50998675fc157dc34c9d2 Mon Sep 17 00:00:00 2001 From: Dongho Kim Date: Sat, 13 Dec 2025 20:46:48 +0100 Subject: [PATCH] update --- .env.example | 1 + .gitignore | 2 +- index.html | 25 +++--- server.js | 28 +++++++ src/App.jsx | 22 ++++- src/components/Admin.jsx | 82 ++++++++++++++++++- src/components/PhotoDetail.jsx | 145 ++++++++++++++++++++++++++++++--- 7 files changed, 279 insertions(+), 26 deletions(-) diff --git a/.env.example b/.env.example index be789c1..0f4e325 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ VITE_ADMIN_PIN=1234 VITE_APP_TITLE=Dongho Kim VITE_APP_DESCRIPTION=My Photo Journey +VITE_APP_TITLE=Dongho Kim Gallery \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4f300fc..f6d7557 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* -docker-compose.yml +docker-compose.yml* node_modules dist dist-ssr diff --git a/index.html b/index.html index e810196..921301e 100644 --- a/index.html +++ b/index.html @@ -1,13 +1,16 @@ - - - - - photo-showcase - - -
- - - + + + + + + photo-showcase + + + +
+ + + + \ No newline at end of file diff --git a/server.js b/server.js index dd4c7ab..d925d40 100644 --- a/server.js +++ b/server.js @@ -201,6 +201,34 @@ app.delete('/api/photos/:id', async (req, res) => { // Serve Uploads app.use('/uploads', express.static(UPLOAD_DIR)); +// Favicon Storage +const faviconStorage = multer.diskStorage({ + destination: (req, file, cb) => { + cb(null, UPLOAD_DIR); + }, + filename: (req, file, cb) => { + cb(null, 'favicon.png'); + } +}); +const uploadFavicon = multer({ storage: faviconStorage }); + +// Upload Favicon +app.post('/api/favicon', uploadFavicon.single('favicon'), (req, res) => { + if (!req.file) return res.status(400).json({ error: 'No file uploaded' }); + res.json({ success: true, url: '/uploads/favicon.png' }); +}); + +// Serve Favicon (Dynamic) +app.get('/api/favicon', (req, res) => { + const faviconPath = path.join(UPLOAD_DIR, 'favicon.png'); + if (fs.existsSync(faviconPath)) { + res.sendFile(faviconPath); + } else { + // Fallback to default + res.status(404).send('Not found'); + } +}); + // Serve Frontend (Production) const DIST_DIR = path.join(__dirname, 'dist'); if (fs.existsSync(DIST_DIR)) { diff --git a/src/App.jsx b/src/App.jsx index 088ddfd..00446dc 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -13,6 +13,10 @@ function App() { const [activePhoto, setActivePhoto] = useState(null); const [photos, setPhotos] = useState([]); + useEffect(() => { + document.title = import.meta.env.VITE_APP_TITLE || 'Chronicle'; + }, []); + // Theme State const [theme, setTheme] = useState(() => { return localStorage.getItem('theme_preference') || 'dark'; @@ -58,7 +62,7 @@ function App() { } return ( -
+
{/* Theme Toggle */}
+ {/* Site Settings */} +
+

+ Site Settings +

+ +
+
+ + setFaviconFile(e.target.files[0])} + style={{ + padding: '0.5rem', + border: '1px solid var(--border)', + borderRadius: '6px', + width: '100%', + background: 'var(--bg-primary)', + color: 'var(--text-primary)' + }} + /> +
+ +
+

+ Upload a .png or .ico file to change the browser tab icon. +

+
+ {/* Delete Confirmation Modal */} {deleteTarget && (
{ const [loaded, setLoaded] = useState(false); + const [isFullScreen, setIsFullScreen] = useState(false); + const [showTitle, setShowTitle] = useState(false); + + const handleScroll = (e) => { + if (e.target.scrollTop > 300) { + setShowTitle(true); + } else { + setShowTitle(false); + } + }; useEffect(() => { setLoaded(true); @@ -29,19 +39,23 @@ const PhotoDetail = ({ photo, onClose }) => { opacity: loaded ? 1 : 0, transition: 'opacity 0.3s ease', overflowY: 'auto' - }}> + }} + onScroll={handleScroll} + > {/* Navbar/Header for the modal */}
+ +
+ {photo.title} +
+ +
{/* Spacer for balance */}
{/* Main Image Area */} -
+ {photo.title} setIsFullScreen(true)} style={{ - width: '100%', - height: '100%', - objectFit: 'contain' + maxWidth: '100%', + maxHeight: '100%', + objectFit: 'contain', + cursor: 'zoom-in', + transition: 'transform 0.2s ease' }} />
@@ -138,15 +174,102 @@ const PhotoDetail = ({ photo, onClose }) => { )}
+ + {/* Footer */} +
+

© {new Date().getFullYear()} {import.meta.env.VITE_APP_TITLE || 'Chronicle'}. All rights reserved.

+
+ + {/* Full Screen Overlay */} + { + isFullScreen && ( +
setIsFullScreen(false)} + style={{ + position: 'fixed', + top: 0, + left: 0, + right: 0, + bottom: 0, + background: 'black', + zIndex: 200, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + cursor: 'zoom-out', + animation: 'fadeIn 0.2s ease-out' + }} + > + {photo.title} + +
+ ) + } + -
+
); };