diff --git a/.gitignore b/.gitignore index a8ab0cc..d0a5ab0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /obj/ /publish/ /appsettings.Production.json +/DEVY.md diff --git a/Endpoints/InfoEndpoint.cs b/Endpoints/InfoEndpoint.cs new file mode 100644 index 0000000..ae57b9e --- /dev/null +++ b/Endpoints/InfoEndpoint.cs @@ -0,0 +1,42 @@ +using System; +using System.IO; +using System.Reflection; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; + +namespace Gott.Endpoints; + +public static class InfoEndpoint +{ + public static void MapInfoEndpoint(this IEndpointRouteBuilder app) + { + app.MapGet("/api/info", HandleInfo); + } + + private static IResult HandleInfo() + { + var assembly = Assembly.GetExecutingAssembly(); + var location = assembly.Location; + + long buildTime = 0; + + if (!string.IsNullOrEmpty(location) && File.Exists(location)) + { + var lastWrite = File.GetLastWriteTimeUtc(location); + buildTime = new DateTimeOffset(lastWrite).ToUnixTimeSeconds(); + } + else + { + var dir = AppContext.BaseDirectory; + var exePath = Path.Combine(dir, "gott"); + if (File.Exists(exePath)) + { + var lastWrite = File.GetLastWriteTimeUtc(exePath); + buildTime = new DateTimeOffset(lastWrite).ToUnixTimeSeconds(); + } + } + + return Results.Json(new { buildTime }); + } +} diff --git a/Program.cs b/Program.cs index 8ba799e..5c27887 100644 --- a/Program.cs +++ b/Program.cs @@ -22,5 +22,6 @@ app.MapHistoryEndpoint(); app.MapSessionEndpoints(); app.MapAgentEndpoints(); app.MapWorkspaceEndpoint(); +app.MapInfoEndpoint(); app.Run("http://0.0.0.0:19000"); diff --git a/deploy.sh b/deploy.sh index ab938c7..6e10d29 100755 --- a/deploy.sh +++ b/deploy.sh @@ -17,7 +17,6 @@ fi export PATH="$HOME/.dotnet:$PATH" dotnet publish -c Release -o publish -cp wwwroot/index.html publish/wwwroot/index.html if [ "$_hostname" = "stein2" ]; then systemctl start gott diff --git a/wwwroot/css/base.css b/wwwroot/css/base.css index 019dd36..2f8eb0f 100644 --- a/wwwroot/css/base.css +++ b/wwwroot/css/base.css @@ -51,7 +51,7 @@ button:not(:disabled):hover, select:hover, input:hover, textarea:hover { } button:disabled { - opacity: .5; + opacity: var(--semi-transparent); } textarea { diff --git a/wwwroot/css/chat.css b/wwwroot/css/chat.css index 79bf627..f17e638 100644 --- a/wwwroot/css/chat.css +++ b/wwwroot/css/chat.css @@ -23,7 +23,7 @@ } .custom-cmd-btn.running { - opacity: 0.5; + opacity: var(--semi-transparent); cursor: wait; } @@ -84,6 +84,7 @@ border-bottom: var(--border-width) solid var(--f1-border); flex-shrink: 0; min-height: 2.5em; + opacity: var(--semi-transparent); } .msg { @@ -130,7 +131,7 @@ padding: var(--s2); background: var(--f1-bg); border: var(--border-width) solid var(--f1-border); - opacity: 0.5; + opacity: var(--semi-transparent); } .input-area { @@ -150,7 +151,6 @@ } .input-area button:disabled { - opacity: 0.5; cursor: not-allowed; } @@ -161,7 +161,7 @@ } .archived { - opacity: 0.6; + opacity: var(--semi-transparent); } .archive-load-btn { @@ -244,7 +244,7 @@ cursor: pointer; padding: var(--s1); color: var(--text); - opacity: 0.6; + opacity: var(--semi-transparent); } .file-remove:hover { @@ -255,7 +255,7 @@ .attachment-indicator { margin-top: var(--s2); - opacity: 0.7; + opacity: var(--semi-transparent); } .attachment-indicator:hover { diff --git a/wwwroot/css/file-explorer.css b/wwwroot/css/file-explorer.css index a298fd3..25aae5f 100644 --- a/wwwroot/css/file-explorer.css +++ b/wwwroot/css/file-explorer.css @@ -39,7 +39,7 @@ } .fe-path { - opacity: 0.6; + opacity: var(--semi-transparent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -49,11 +49,6 @@ padding: var(--s1) var(--s2); } -.fe-btn:disabled { - opacity: 0.4; - cursor: default; -} - .fe-body { display: flex; flex: 1; @@ -102,13 +97,12 @@ .fe-file { color: var(--text); - opacity: 0.85; } .fe-loading, .fe-error, .fe-empty, .fe-placeholder { padding: var(--s4); text-align: center; - opacity: 0.5; + opacity: var(--semi-transparent); align-self: center; margin: auto; } @@ -128,7 +122,7 @@ padding-right: var(--s3); background: var(--f1-bg); color: var(--text); - opacity: 0.35; + opacity: var(--semi-transparent); text-align: right; overflow: hidden; user-select: none; @@ -184,7 +178,7 @@ } .fe-info { - opacity: 0.6; + opacity: var(--semi-transparent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; diff --git a/wwwroot/css/theme.css b/wwwroot/css/theme.css index 61a49e3..d4d84b8 100644 --- a/wwwroot/css/theme.css +++ b/wwwroot/css/theme.css @@ -13,4 +13,5 @@ --s3: .75em; --s4: 1em; --border-width: 1px; + --semi-transparent: 0.6; } diff --git a/wwwroot/index.html b/wwwroot/index.html index 00fbf87..00e04a8 100644 --- a/wwwroot/index.html +++ b/wwwroot/index.html @@ -3,7 +3,8 @@ - Gott + // gott + @@ -133,8 +134,8 @@ -
+
diff --git a/wwwroot/js/title.js b/wwwroot/js/title.js new file mode 100644 index 0000000..ebceff5 --- /dev/null +++ b/wwwroot/js/title.js @@ -0,0 +1,18 @@ +let buildTime = 0; + +fetch('/api/info').then(r => r.json()).then(data => { + buildTime = data.buildTime || 0; + updateTitle(); + setInterval(updateTitle, 1000); +}); + +function updateTitle() { + if (!buildTime) { document.title = '// gott'; return; } + const s = Math.floor(Date.now() / 1000) - buildTime; + let ago; + if (s < 60) ago = `${s} Sekunde${s !== 1 ? 'n' : ''}`; + else if (s < 3600) { const m = Math.floor(s / 60); ago = `${m} Minute${m !== 1 ? 'n' : ''}`; } + else if (s < 86400) { const h = Math.floor(s / 3600); ago = `${h} Stunde${h !== 1 ? 'n' : ''}`; } + else { const d = Math.floor(s / 86400); ago = `${d} Tag${d !== 1 ? 'en' : ''}`; } + document.title = `// gott :: Build vor ${ago}`; +}