feat: Semantische Versionierung mit Git-Tags und App-Footer.
VERSION-Datei (0.1.0.0), Release-Flow in update-prod.sh und Build-time-Einbindung der Versionsnummer im Footer mit Copyright-Link. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+8
-4
@@ -2,12 +2,16 @@
|
||||
FROM node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
ARG APP_VERSION=0.1.0.0-dev
|
||||
ENV VITE_APP_VERSION=$APP_VERSION
|
||||
|
||||
# Install dependencies
|
||||
COPY package*.json ./
|
||||
COPY client/package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
# Copy code and build production bundle
|
||||
COPY . .
|
||||
# Copy client sources and repo version file
|
||||
COPY client/ .
|
||||
COPY VERSION ./VERSION
|
||||
RUN npm run build
|
||||
|
||||
# --- Production Stage ---
|
||||
@@ -15,7 +19,7 @@ FROM nginx:1.25-alpine
|
||||
WORKDIR /usr/share/nginx/html
|
||||
|
||||
# Copy custom Nginx configuration
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY client/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Copy built assets from builder
|
||||
COPY --from=builder /app/dist .
|
||||
|
||||
+45
-1
@@ -1949,7 +1949,7 @@ body:has(.theme-cupertino) {
|
||||
position: fixed;
|
||||
left: 16px;
|
||||
right: 16px;
|
||||
bottom: calc(16px + env(safe-area-inset-bottom, 0px));
|
||||
bottom: calc(36px + env(safe-area-inset-bottom, 0px));
|
||||
z-index: 1200;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
@@ -2107,4 +2107,48 @@ body:has(.theme-cupertino) {
|
||||
}
|
||||
}
|
||||
|
||||
.app-version-footer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 900;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
padding: 6px 12px calc(6px + env(safe-area-inset-bottom, 0px));
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
color: #64748b;
|
||||
background: rgba(11, 12, 16, 0.72);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.06);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.app-version-footer a,
|
||||
.app-version-footer button {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.app-version-footer__version {
|
||||
font-variant-numeric: tabular-nums;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.app-version-footer__sep {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.app-version-footer__copyright {
|
||||
color: #94a3b8;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.app-version-footer__copyright:hover {
|
||||
color: #e2e8f0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import { getActiveMasterKey, logoutUser } from './services/auth.js'
|
||||
import { startBackgroundSync, stopBackgroundSync, syncAllLogbooks, subscribeToSyncState } from './services/sync.js'
|
||||
import ReadOnlyViewer from './components/ReadOnlyViewer.tsx'
|
||||
import PwaInstallPrompt from './components/PwaInstallPrompt.tsx'
|
||||
import AppFooter from './components/AppFooter.tsx'
|
||||
import { db } from './services/db.js'
|
||||
import { useLiveQuery } from 'dexie-react-hooks'
|
||||
import { Ship, LogOut, ChevronLeft, Users, Compass, FileText, Settings, Wifi, WifiOff } from 'lucide-react'
|
||||
@@ -319,6 +320,7 @@ export default function AppWrapper() {
|
||||
return (
|
||||
<DialogProvider>
|
||||
<App />
|
||||
<AppFooter />
|
||||
</DialogProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
const APP_VERSION = typeof __APP_VERSION__ !== 'undefined' ? __APP_VERSION__ : 'dev'
|
||||
|
||||
export default function AppFooter() {
|
||||
return (
|
||||
<footer className="app-version-footer">
|
||||
<span className="app-version-footer__version">v{APP_VERSION}</span>
|
||||
<span className="app-version-footer__sep" aria-hidden="true">
|
||||
·
|
||||
</span>
|
||||
<a className="app-version-footer__copyright" href="mailto:elpatron+kd@mailbox.org">
|
||||
© 2026 Markus F.J. Busche
|
||||
</a>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare const __APP_VERSION__: string
|
||||
@@ -1,9 +1,28 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { VitePWA } from 'vite-plugin-pwa'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { resolve, dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
function readAppVersion(): string {
|
||||
if (process.env.VITE_APP_VERSION) {
|
||||
return process.env.VITE_APP_VERSION.trim()
|
||||
}
|
||||
try {
|
||||
return readFileSync(resolve(__dirname, '../VERSION'), 'utf8').trim()
|
||||
} catch {
|
||||
return '0.1.0.0-dev'
|
||||
}
|
||||
}
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
define: {
|
||||
__APP_VERSION__: JSON.stringify(readAppVersion())
|
||||
},
|
||||
server: {
|
||||
port: 5173,
|
||||
proxy: {
|
||||
|
||||
Reference in New Issue
Block a user