From a2cae3f066a923a24d0269645bb9dec550e0fec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Kr=C3=BChlmann?= Date: Thu, 15 Jan 2026 14:38:06 +0100 Subject: [PATCH] Add staging banner --- README.md | 1 + .../imgfloat/controller/ViewController.java | 18 +++++++++++- src/main/resources/static/css/styles.css | 28 +++++++++++++++++++ src/main/resources/templates/admin.html | 3 +- src/main/resources/templates/cookies.html | 3 +- src/main/resources/templates/dashboard.html | 3 +- src/main/resources/templates/error.html | 3 +- .../templates/fragments/staging.html | 8 ++++++ src/main/resources/templates/index.html | 3 +- src/main/resources/templates/privacy.html | 3 +- src/main/resources/templates/settings.html | 3 +- src/main/resources/templates/terms.html | 3 +- 12 files changed, 70 insertions(+), 9 deletions(-) create mode 100644 src/main/resources/templates/fragments/staging.html diff --git a/README.md b/README.md index 1044fac..f7aabf2 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Optional: | Variable | Description | Example Value | |----------|-------------|---------------| | `IMGFLOAT_COMMIT_URL_PREFIX` | Git commit URL prefix used for the build link badge (unset to hide the badge) | https://github.com/imgfloat/server/commit/ | +| `IMGFLOAT_IS_STAGING` | Show a staging warning banner on non-broadcast pages when set to `1` | 1 | | `IMGFLOAT_MARKETPLACE_SCRIPTS_PATH` | Filesystem path to marketplace script seed directories (each containing `metadata.json`, optional `source.js`, optional `logo.png`, and optional `attachments/`) | /var/imgfloat/marketplace-scripts | | `IMGFLOAT_SYSADMIN_CHANNEL_ACCESS_ENABLED` | Allow sysadmins to manage any channel without being listed as a channel admin | true | | `TWITCH_REDIRECT_URI` | Override default redirect URI | http://localhost:8080/login/oauth2/code/twitch | diff --git a/src/main/java/dev/kruhlmann/imgfloat/controller/ViewController.java b/src/main/java/dev/kruhlmann/imgfloat/controller/ViewController.java index 4fa592b..45a251a 100644 --- a/src/main/java/dev/kruhlmann/imgfloat/controller/ViewController.java +++ b/src/main/java/dev/kruhlmann/imgfloat/controller/ViewController.java @@ -16,6 +16,7 @@ import dev.kruhlmann.imgfloat.service.VersionService; import dev.kruhlmann.imgfloat.util.LogSanitizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -34,6 +35,7 @@ public class ViewController { private final GithubReleaseService githubReleaseService; private final SystemAdministratorService systemAdministratorService; private final long uploadLimitBytes; + private final boolean isStaging; public ViewController( ChannelDirectoryService channelDirectoryService, @@ -44,7 +46,8 @@ public class ViewController { AuthorizationService authorizationService, GithubReleaseService githubReleaseService, SystemAdministratorService systemAdministratorService, - long uploadLimitBytes + long uploadLimitBytes, + @Value("${IMGFLOAT_IS_STAGING:0}") String isStagingFlag ) { this.channelDirectoryService = channelDirectoryService; this.versionService = versionService; @@ -55,6 +58,7 @@ public class ViewController { this.githubReleaseService = githubReleaseService; this.systemAdministratorService = systemAdministratorService; this.uploadLimitBytes = uploadLimitBytes; + this.isStaging = "1".equals(isStagingFlag); } @org.springframework.web.bind.annotation.GetMapping("/") @@ -67,9 +71,11 @@ public class ViewController { model.addAttribute("channel", sessionUsername); model.addAttribute("adminChannels", channelDirectoryService.adminChannelsFor(sessionUsername)); model.addAttribute("isSystemAdmin", authorizationService.userIsSystemAdministrator(sessionUsername)); + addStagingAttribute(model); addVersionAttributes(model); return "dashboard"; } + addStagingAttribute(model); addVersionAttributes(model); return "index"; } @@ -77,6 +83,7 @@ public class ViewController { @org.springframework.web.bind.annotation.GetMapping("/channels") public String channelDirectory(Model model) { LOG.info("Rendering channel directory"); + addStagingAttribute(model); addVersionAttributes(model); return "channels"; } @@ -84,6 +91,7 @@ public class ViewController { @org.springframework.web.bind.annotation.GetMapping("/terms") public String termsOfUse(Model model) { LOG.info("Rendering terms of use"); + addStagingAttribute(model); addVersionAttributes(model); return "terms"; } @@ -91,6 +99,7 @@ public class ViewController { @org.springframework.web.bind.annotation.GetMapping("/privacy") public String privacyPolicy(Model model) { LOG.info("Rendering privacy policy"); + addStagingAttribute(model); addVersionAttributes(model); return "privacy"; } @@ -98,6 +107,7 @@ public class ViewController { @org.springframework.web.bind.annotation.GetMapping("/cookies") public String cookiePolicy(Model model) { LOG.info("Rendering cookie policy"); + addStagingAttribute(model); addVersionAttributes(model); return "cookies"; } @@ -116,6 +126,7 @@ public class ViewController { throw new ResponseStatusException(INTERNAL_SERVER_ERROR, "Failed to serialize settings"); } model.addAttribute("initialSysadmin", systemAdministratorService.getInitialSysadmin()); + addStagingAttribute(model); return "settings"; } @@ -144,6 +155,7 @@ public class ViewController { LOG.error("Failed to serialize settings for admin view", e); throw new ResponseStatusException(INTERNAL_SERVER_ERROR, "Failed to serialize settings"); } + addStagingAttribute(model); return "admin"; } @@ -167,4 +179,8 @@ public class ViewController { model.addAttribute("buildCommitShort", gitInfoService.getShortCommitSha()); model.addAttribute("buildCommitUrl", gitInfoService.getCommitUrl()); } + + private void addStagingAttribute(Model model) { + model.addAttribute("isStaging", isStaging); + } } diff --git a/src/main/resources/static/css/styles.css b/src/main/resources/static/css/styles.css index 8dc5eeb..c893d2e 100644 --- a/src/main/resources/static/css/styles.css +++ b/src/main/resources/static/css/styles.css @@ -22,6 +22,34 @@ body { padding: 0; } +body.has-staging-banner { + padding-top: 44px; +} + +.staging-banner { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1000; + padding: 8px 16px; + text-align: center; + font-size: 12px; + letter-spacing: 0.18em; + text-transform: uppercase; + font-weight: 700; + background: repeating-linear-gradient(135deg, #111827 0 18px, #facc15 18px 36px); +} + +.staging-banner span { + display: inline-block; + padding: 4px 12px; + border-radius: 999px; + background: #111827; + color: #facc15; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35); +} + .landing-body { min-height: 100vh; background: diff --git a/src/main/resources/templates/admin.html b/src/main/resources/templates/admin.html index 625bc6b..9186053 100644 --- a/src/main/resources/templates/admin.html +++ b/src/main/resources/templates/admin.html @@ -29,7 +29,8 @@ - + +
diff --git a/src/main/resources/templates/cookies.html b/src/main/resources/templates/cookies.html index 9b1671d..2504382 100644 --- a/src/main/resources/templates/cookies.html +++ b/src/main/resources/templates/cookies.html @@ -6,7 +6,8 @@ - + +
diff --git a/src/main/resources/templates/dashboard.html b/src/main/resources/templates/dashboard.html index 699398d..fc2f1db 100644 --- a/src/main/resources/templates/dashboard.html +++ b/src/main/resources/templates/dashboard.html @@ -8,7 +8,8 @@ - + +
diff --git a/src/main/resources/templates/error.html b/src/main/resources/templates/error.html index 7c42215..483e122 100644 --- a/src/main/resources/templates/error.html +++ b/src/main/resources/templates/error.html @@ -6,7 +6,8 @@ - + +
diff --git a/src/main/resources/templates/fragments/staging.html b/src/main/resources/templates/fragments/staging.html new file mode 100644 index 0000000..e6f9fb6 --- /dev/null +++ b/src/main/resources/templates/fragments/staging.html @@ -0,0 +1,8 @@ + + + +
+ Staging environment +
+ + diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 23d2288..89949a3 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -6,7 +6,8 @@ - + +
diff --git a/src/main/resources/templates/privacy.html b/src/main/resources/templates/privacy.html index 5566c5c..f1f142b 100644 --- a/src/main/resources/templates/privacy.html +++ b/src/main/resources/templates/privacy.html @@ -6,7 +6,8 @@ - + +
diff --git a/src/main/resources/templates/settings.html b/src/main/resources/templates/settings.html index a733180..f41ef9d 100644 --- a/src/main/resources/templates/settings.html +++ b/src/main/resources/templates/settings.html @@ -18,7 +18,8 @@ - + +
diff --git a/src/main/resources/templates/terms.html b/src/main/resources/templates/terms.html index 9a32e6e..d0d0639 100644 --- a/src/main/resources/templates/terms.html +++ b/src/main/resources/templates/terms.html @@ -6,7 +6,8 @@ - + +