From 2ba3ab4c86105b1f355813ce62f67b8908121876 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Thu, 25 Feb 2010 12:10:10 -0800 Subject: [PATCH] Theme the web UI with different skin colors We now offer a few of our color choices as configuration settings in gerrit.config, so the administrator can try to style the site to better match their header and other local website conventions. Change-Id: I096f8a2bbdfcf1593a6efcf1031d12852b5bd255 Signed-off-by: Shawn O. Pearce --- Documentation/config-gerrit.txt | 44 ++++++ .../gerrit/common/data/GerritConfig.java | 46 ++++++ .../java/com/google/gerrit/client/Gerrit.java | 143 +++++++++--------- .../java/com/google/gerrit/client/gerrit.css | 127 +++++++++------- .../com/google/gerrit/client/gwt_override.css | 23 ++- .../gerrit/httpd/GerritConfigProvider.java | 19 +++ 6 files changed, 272 insertions(+), 130 deletions(-) diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt index df409bde39..592dfb3827 100644 --- a/Documentation/config-gerrit.txt +++ b/Documentation/config-gerrit.txt @@ -1380,6 +1380,50 @@ Supported MACs: hmac-md5, hmac-md5-96, hmac-sha1, hmac-sha1-96. + By default, all supported MACs are available. +[[theme]] Section theme +~~~~~~~~~~~~~~~~~~~~~~~ + +[[theme.backgroundColor]]theme.backgroundColor:: ++ +Background color for the page, and major data tables like the all +open changes table or the account dashboard. The value must be a +valid HTML hex color code, or standard color name. ++ +By default white, `FFFFFF`. + +[[theme.topMenuColor]]theme.topMenuColor:: ++ +This is the color of the main menu bar at the top of the page. +The value must be a valid HTML hex color code, or standard color +name. The value defaults to <>. + +[[theme.textColor]]theme.textColor:: ++ +Text color for the page, and major data tables like the all +open changes table or the account dashboard. The value must be a +valid HTML hex color code, or standard color name. ++ +By default black, `000000`. + +[[theme.trimColor]]theme.trimColor:: ++ +Primary color used as a background color behind text. This is +the color of the main menu bar at the top, of table headers, +and of major UI areas that we want to offset from other portions +of the page. The value must be a valid HTML hex color code, or +standard color name. ++ +By default a shade of green, `D4E9A9`. + +[[theme.selectionColor]]theme.selectionColor:: ++ +Background color used within a trimColor area to denote the currently +selected tab, or the background color used in a table to denote the +currently selected row. The value must be a valid HTML hex color +code, or standard color name. ++ +By default a shade of yellow, `FFFFCC`. + [[user]] Section user ~~~~~~~~~~~~~~~~~~~~~ diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java index 5ff666d86d..175bfb7aac 100644 --- a/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java +++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/GerritConfig.java @@ -38,6 +38,12 @@ public class GerritConfig implements Cloneable { protected List commentLinks; protected boolean documentationAvailable; + protected String backgroundColor; + protected String topMenuColor; + protected String textColor; + protected String trimColor; + protected String selectionColor; + public String getRegisterUrl() { return registerUrl; } @@ -148,4 +154,44 @@ public class GerritConfig implements Cloneable { public void setDocumentationAvailable(final boolean available) { documentationAvailable = available; } + + public String getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(String color) { + backgroundColor = color; + } + + public String getTopMenuColor() { + return topMenuColor; + } + + public void setTopMenuColor(String color) { + topMenuColor = color; + } + + public String getTextColor() { + return textColor; + } + + public void setTextColor(String color) { + textColor = color; + } + + public String getTrimColor() { + return trimColor; + } + + public void setTrimColor(String color) { + trimColor = color; + } + + public String getSelectionColor() { + return selectionColor; + } + + public void setSelectionColor(String color) { + selectionColor = color; + } } diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java index d26d7362c7..707c89f09e 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/Gerrit.java @@ -219,74 +219,8 @@ public class Gerrit implements EntryPoint { /*-{ return path.replace(/%2F/g, "/"); }-*/; }); - RESOURCES.gwt_override().ensureInjected(); - RESOURCES.css().ensureInjected(); - - final RootPanel gTopMenu = RootPanel.get("gerrit_topmenu"); - final RootPanel gStarting = RootPanel.get("gerrit_startinggerrit"); - final RootPanel gBody = RootPanel.get("gerrit_body"); - final RootPanel gBottomMenu = RootPanel.get("gerrit_btmmenu"); - - gTopMenu.setStyleName(RESOURCES.css().gerritTopMenu()); - gBody.setStyleName(RESOURCES.css().gerritBody()); - initHostname(); Window.setTitle(M.windowTitle1(myHost)); - initHistoryHooks(); - populateBottomMenu(gBottomMenu); - - final Grid menuLine = new Grid(1, 3); - menuLeft = new TabPanel(); - menuRight = new LinkMenuBar(); - searchPanel = new SearchPanel(); - menuLeft.setStyleName(RESOURCES.css().topmenuMenuLeft()); - menuLine.setStyleName(RESOURCES.css().topmenu()); - gTopMenu.add(menuLine); - final FlowPanel menuRightPanel = new FlowPanel(); - menuRightPanel.setStyleName(RESOURCES.css().topmenuMenuRight()); - menuRightPanel.add(menuRight); - menuRightPanel.add(searchPanel); - menuLine.setWidget(0, 0, menuLeft); - menuLine.setWidget(0, 1, new FlowPanel()); - menuLine.setWidget(0, 2, menuRightPanel); - final CellFormatter fmt = menuLine.getCellFormatter(); - fmt.setStyleName(0, 0, RESOURCES.css().topmenuTDmenu()); - fmt.setStyleName(0, 1, RESOURCES.css().topmenuTDglue()); - fmt.setStyleName(0, 2, RESOURCES.css().topmenuTDmenu()); - - siteHeader = RootPanel.get("gerrit_header"); - siteFooter = RootPanel.get("gerrit_footer"); - - body = new ViewSite() { - @Override - protected void onShowView(Screen view) { - final String token = view.getToken(); - if (!token.equals(History.getToken())) { - History.newItem(token, false); - if (historyHooks != null) { - dispatchHistoryHooks(token); - } - } - super.onShowView(view); - view.onShowView(); - } - }; - gBody.add(body); - - RpcStatus.INSTANCE = new RpcStatus(gTopMenu); - JsonUtil.addRpcStartHandler(RpcStatus.INSTANCE); - JsonUtil.addRpcCompleteHandler(RpcStatus.INSTANCE); - JsonUtil.setDefaultXsrfManager(new XsrfManager() { - @Override - public String getToken(JsonDefTarget proxy) { - return Cookies.getCookie(SESSION_COOKIE); - } - - @Override - public void setToken(JsonDefTarget proxy, String token) { - // Ignore the request, we always rely upon the cookie. - } - }); final HostPageDataService hpd = GWT.create(HostPageDataService.class); hpd.load(new GerritCallback() { @@ -296,7 +230,7 @@ public class Gerrit implements EntryPoint { myAccount = result.account; applyUserPreferences(); } - onModuleLoad2(gStarting); + onModuleLoad2(); } }); } @@ -362,11 +296,78 @@ public class Gerrit implements EntryPoint { btmmenu.add(version); } - private void onModuleLoad2(final RootPanel starting) { - refreshMenuBar(); + private void onModuleLoad2() { + RESOURCES.gwt_override().ensureInjected(); + RESOURCES.css().ensureInjected(); - starting.getElement().getParentElement().removeChild(starting.getElement()); - RootPanel.detachNow(starting); + final RootPanel gTopMenu = RootPanel.get("gerrit_topmenu"); + final RootPanel gStarting = RootPanel.get("gerrit_startinggerrit"); + final RootPanel gBody = RootPanel.get("gerrit_body"); + final RootPanel gBottomMenu = RootPanel.get("gerrit_btmmenu"); + + gTopMenu.setStyleName(RESOURCES.css().gerritTopMenu()); + gBody.setStyleName(RESOURCES.css().gerritBody()); + + final Grid menuLine = new Grid(1, 3); + menuLeft = new TabPanel(); + menuRight = new LinkMenuBar(); + searchPanel = new SearchPanel(); + menuLeft.setStyleName(RESOURCES.css().topmenuMenuLeft()); + menuLine.setStyleName(RESOURCES.css().topmenu()); + gTopMenu.add(menuLine); + final FlowPanel menuRightPanel = new FlowPanel(); + menuRightPanel.setStyleName(RESOURCES.css().topmenuMenuRight()); + menuRightPanel.add(menuRight); + menuRightPanel.add(searchPanel); + menuLine.setWidget(0, 0, menuLeft); + menuLine.setWidget(0, 1, new FlowPanel()); + menuLine.setWidget(0, 2, menuRightPanel); + final CellFormatter fmt = menuLine.getCellFormatter(); + fmt.setStyleName(0, 0, RESOURCES.css().topmenuTDmenu()); + fmt.setStyleName(0, 1, RESOURCES.css().topmenuTDglue()); + fmt.setStyleName(0, 2, RESOURCES.css().topmenuTDmenu()); + + siteHeader = RootPanel.get("gerrit_header"); + siteFooter = RootPanel.get("gerrit_footer"); + + body = new ViewSite() { + @Override + protected void onShowView(Screen view) { + final String token = view.getToken(); + if (!token.equals(History.getToken())) { + History.newItem(token, false); + if (historyHooks != null) { + dispatchHistoryHooks(token); + } + } + super.onShowView(view); + view.onShowView(); + } + }; + gBody.add(body); + + RpcStatus.INSTANCE = new RpcStatus(gTopMenu); + JsonUtil.addRpcStartHandler(RpcStatus.INSTANCE); + JsonUtil.addRpcCompleteHandler(RpcStatus.INSTANCE); + JsonUtil.setDefaultXsrfManager(new XsrfManager() { + @Override + public String getToken(JsonDefTarget proxy) { + return Cookies.getCookie(SESSION_COOKIE); + } + + @Override + public void setToken(JsonDefTarget proxy, String token) { + // Ignore the request, we always rely upon the cookie. + } + }); + + gStarting.getElement().getParentElement().removeChild( + gStarting.getElement()); + RootPanel.detachNow(gStarting); + + initHistoryHooks(); + populateBottomMenu(gBottomMenu); + refreshMenuBar(); History.addValueChangeHandler(new ValueChangeHandler() { public void onValueChange(final ValueChangeEvent event) { diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css index 061ae25c01..4c5729dd32 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css @@ -14,6 +14,7 @@ */ @external .gwt-Button; +@external .gwt-TabBar; @external .gwt-TabBarFirst; @external .gwt-TabBarItem; @external .gwt-TabBarItem-selected; @@ -34,10 +35,15 @@ @def black #000000; @def white #ffffff; -@def trim-color #D4E9A9; @def norm-font Arial Unicode MS, Arial, sans-serif; @def mono-font 'Lucida Console', 'Lucida Sans Typewriter', Monaco, monospace; +@eval backgroundColor com.google.gerrit.client.Gerrit.getConfig().getBackgroundColor(); +@eval topMenuColor com.google.gerrit.client.Gerrit.getConfig().getTopMenuColor(); +@eval textColor com.google.gerrit.client.Gerrit.getConfig().getTextColor();; +@eval trimColor com.google.gerrit.client.Gerrit.getConfig().getTrimColor(); +@eval selectionColor com.google.gerrit.client.Gerrit.getConfig().getSelectionColor(); + @sprite .greenCheckClass { gwt-image: "greenCheck"; @@ -48,8 +54,17 @@ padding-top: 5px; padding-left: 5px; padding-right: 5px; - background: trim-color; + background: topMenuColor; } +.gerritTopMenu .gwt-TabBar .gwt-TabBarItem, +.gerritTopMenu .gwt-TabBar .gwt-TabBarRest, +.gerritTopMenu .gwt-TabBar .gwt-TabPanelBottom { + background: topMenuColor; +} +.gerritTopMenu .gwt-TabBar .gwt-TabBarItem-selected { + background: selectionColor; +} + .gerritBody { font-size: 11pt; padding-left: 5px; @@ -93,7 +108,7 @@ .blockHeader { font-size: small; font-weight: bold; - background: trim-color; + background: trimColor; padding: 0.2em 0.2em 0.2em 0.5em; } @@ -208,16 +223,16 @@ } .topmenuMenuLeft { width: 300px; - border-left: 1px solid trim-color; - border-right: 1px solid trim-color; - border-bottom: 1px solid trim-color; + border-left: 1px solid topMenuColor; + border-right: 1px solid topMenuColor; + border-bottom: 1px solid topMenuColor; } .topmenuMenuLeft .gwt-TabBarFirst { display: none; } .topmenuMenuLeft .gwt-TabBarItem { margin: 0px; - background: trim-color; + background: topMenuColor; padding-top: 0px; padding-bottom: 1px; padding-left: 1em; @@ -225,14 +240,14 @@ border-right: 1px solid black; } .topmenuMenuLeft .gwt-TabBarItem-selected { - background: #ffffcc; + background: selectionColor; } .topmenuMenuLeft .gwt-TabBarRest { - background: trim-color; + background: topMenuColor; padding-top: 0px; } .topmenuMenuLeft .gwt-TabPanelBottom { - background: trim-color; + background: topMenuColor; border-top: none; border-left: none; border-right: none; @@ -295,7 +310,7 @@ border: none; padding: 10px; width: 600px; - color: white; + color: backgroundColor; font-size: 15px; font-family: verdana; } @@ -356,15 +371,15 @@ width: 1px; padding: 0px; vertical-align: middle; - border-bottom: 1px solid trim-color; + border-bottom: 1px solid trimColor; } .changeTable .changeTypeCell { width: 1px; padding-left: 5px; padding-right: 5px; - border-right: 1px solid trim-color; - border-bottom: 1px solid trim-color; + border-right: 1px solid trimColor; + border-bottom: 1px solid trimColor; vertical-align: top; } @@ -391,14 +406,14 @@ } .changeTable .leftMostCell { - border-left: 1px solid trim-color; + border-left: 1px solid trimColor; } .changeTable .dataCell { padding-left: 5px; padding-right: 5px; - border-right: 1px solid trim-color; - border-bottom: 1px solid trim-color; + border-right: 1px solid trimColor; + border-bottom: 1px solid trimColor; } .accountDashboard.changeTable tr { @@ -409,15 +424,17 @@ color: #444444; text-decoration: none; } -.accountDashboard.changeTable .needsReview { +.accountDashboard.changeTable .needsReview, +.accountDashboard.changeTable .needsReview a { font-weight: bold; - color: black; - background: white; + color: textColor; + background: backgroundColor; } .changeTable .activeRow, -.accountDashboard.changeTable .activeRow { - background: #ffffcc; +.accountDashboard.changeTable .activeRow, +.accountDashboard.changeTable .activeRow a { + background: selectionColor; } .changeTable .cID { @@ -459,33 +476,33 @@ } .changeTable .iconHeader { - border-top: 1px solid white; - border-bottom: 1px solid white; - background-color: trim-color; + border-top: 1px solid backgroundColor; + border-bottom: 1px solid backgroundColor; + background-color: trimColor; } .changeTable .dataHeader { - border: 1px solid white; + border: 1px solid backgroundColor; padding: 2px 6px 1px; - background-color: trim-color; + background-color: trimColor; font-style: italic; white-space: nowrap; - color: black; + color: textColor; } .changeTable .sectionHeader { - border-top: 8px solid white; + border-top: 8px solid backgroundColor; padding: 2px 6px 1px; - background-color: trim-color; + background-color: trimColor; white-space: nowrap; font-weight: bold; - color: black; + color: textColor; } .changeTable .emptySection { - border-left: 1px solid trim-color; - border-right: 1px solid trim-color; - border-bottom: 1px solid trim-color; + border-left: 1px solid trimColor; + border-right: 1px solid trimColor; + border-bottom: 1px solid trimColor; font-style: italic; padding-left: 25px; } @@ -515,6 +532,8 @@ width: 100%; border-collapse: separate; border-spacing: 0; + background: white; + color: black; } .patchContentTable td { padding-top: 0; @@ -598,13 +617,13 @@ border-bottom: 1px solid white; } .fileColumnHeader { - background: trim-color; + background: trimColor; font-family: norm-font; font-weight: bold; text-align: center; } .lineNumber.fileColumnHeader { - border-bottom: 1px solid trim-color; + border-bottom: 1px solid trimColor; } .noLineLineNumber { font-family: mono-font; @@ -658,7 +677,7 @@ .patchContentTable .activeRow .iconCell, .patchContentTable .activeRow .lineNumber { - background: #ffffcc; + background: selectionColor; } .patchContentTable .activeRow .iconCell, .patchContentTable .activeRow .lineNumber, @@ -725,13 +744,13 @@ } .infoTable td { - border-left: 1px solid trim-color; - border-bottom: 1px solid trim-color; + border-left: 1px solid trimColor; + border-bottom: 1px solid trimColor; padding: 2px 6px 1px; } .infoTable td.header { - background-color: trim-color; + background-color: trimColor; font-weight: normal; padding: 2px 4px 0 6px; font-style: italic; @@ -741,7 +760,7 @@ } .rightmost { - border-right: 1px solid trim-color; + border-right: 1px solid trimColor; } .infoTable td.approvalrole { @@ -780,18 +799,18 @@ .infoBlock td { padding: 2px 4px 2px 6px; - border-right: 1px solid trim-color; - border-bottom: 1px solid trim-color; + border-right: 1px solid trimColor; + border-bottom: 1px solid trimColor; text-align: left; white-space: nowrap; } .infoBlock td.topmost { - border-top: 1px solid trim-color; + border-top: 1px solid trimColor; } .infoBlock td.header { - background-color: trim-color; + background-color: trimColor; font-style: italic; text-align: right; } @@ -801,7 +820,7 @@ } .infoBlock td.bottomheader { - border-bottom: 1px solid trim-color; + border-bottom: 1px solid trimColor; } .infoBlock td.closedstate { @@ -867,7 +886,7 @@ td.downloadLinkListCell { padding: 0px; } .downloadLinkHeader { - background: trim-color; + background: trimColor; white-space: nowrap; border-bottom: 1px solid black; } @@ -882,7 +901,7 @@ td.downloadLinkListCell { color: black; text-decoration: none; white-space: nowrap; - background: trim-color; + background: trimColor; border-right: 1px solid black; padding-left: 0.5em; padding-right: 0.5em; @@ -891,7 +910,7 @@ a:hover.downloadLink { color: black; } .downloadLink_Active { - background: #ffffcc; + background: selectionColor; } .downloadLinkCopyLabel { white-space: pre; @@ -982,13 +1001,13 @@ a:hover.downloadLink { .addSshKeyPanel { margin-top: 10px; - background-color: trim-color; + background-color: trimColor; padding: 5px 5px 5px 5px; } .sshHostKeyPanel { margin-top: 10px; - border: 1px solid trim-color; + border: 1px solid trimColor; padding: 5px 5px 5px 5px; } .sshHostKeyPanelHeading { @@ -1084,7 +1103,7 @@ a:hover.downloadLink { .publishCommentsScreen .approvalCategoryList { margin-bottom: 10px; margin-left: 10px; - background: trim-color; + background: trimColor; width: 25em; white-space: nowrap; padding-top: 2px; @@ -1139,7 +1158,7 @@ a:hover.downloadLink { } .abandonChangeDialog .abandonMessage { margin-left: 10px; - background: trim-color; + background: trimColor; padding: 5px 5px 5px 5px; } .abandonChangeDialog .abandonMessage textarea { @@ -1156,7 +1175,7 @@ a:hover.downloadLink { opacity: 0.90; } .patchBrowserPopupBody { - background: white; + background: backgroundColor; margin: 4px; opacity: 0.90; } diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gwt_override.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gwt_override.css index d709e6a64e..b238292d4e 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gwt_override.css +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gwt_override.css @@ -14,6 +14,7 @@ */ @external .gwt-Button; +@external .gwt-DialogBox .dialogMiddleCenter; @external .gwt-TabBar; @external .gwt-TabBarFirst; @external .gwt-TabBarItem; @@ -22,8 +23,20 @@ @external .gwt-TabPanel; @external .gwt-TabPanelBottom; -@def trim-color #D4E9A9; +@eval backgroundColor com.google.gerrit.client.Gerrit.getConfig().getBackgroundColor(); +@eval textColor com.google.gerrit.client.Gerrit.getConfig().getTextColor();; +@eval trimColor com.google.gerrit.client.Gerrit.getConfig().getTrimColor(); +@eval selectionColor com.google.gerrit.client.Gerrit.getConfig().getSelectionColor(); +body { + background: backgroundColor; + color: textColor; +} + +.gwt-DialogBox .dialogMiddleCenter { + background: backgroundColor; + color: textColor; +} .gwt-Button { white-space: nowrap; @@ -37,7 +50,7 @@ } .gwt-TabBar .gwt-TabBarItem { margin: 0px; - background: trim-color; + background: trimColor; padding-top: 0.5em; padding-bottom: 1px; padding-left: 1em; @@ -45,15 +58,15 @@ border-right: 1px solid black; } .gwt-TabBar .gwt-TabBarItem-selected { - background: #ffffcc; + background: selectionColor; } .gwt-TabBar .gwt-TabBarRest { - background: trim-color; + background: trimColor; padding-top: 0.5em; padding-bottom: 1px; } .gwt-TabBar .gwt-TabPanelBottom { - background: trim-color; + background: trimColor; border-top: 1px solid black; border-left: none; border-right: none; diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java index fff3952583..6570ff1dd3 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/GerritConfigProvider.java @@ -142,9 +142,28 @@ class GerritConfigProvider implements Provider { } config.setCommentLinks(links); + config.setBackgroundColor(getThemeColor("backgroundColor", "#FFFFFF")); + config.setTextColor(getThemeColor("textColor", "#000000")); + config.setTrimColor(getThemeColor("trimColor", "#D4E9A9")); + config.setSelectionColor(getThemeColor("selectionColor", "#FFFFCC")); + + config + .setTopMenuColor(getThemeColor("topMenuColor", config.getTrimColor())); + return config; } + private String getThemeColor(String name, String defaultValue) { + String v = cfg.getString("theme", null, name); + if (v == null || v.isEmpty()) { + v = defaultValue; + } + if (!v.startsWith("#") && v.matches("^[0-9a-fA-F]{2,6}$")) { + v = "#" + v; + } + return v; + } + @Override public GerritConfig get() { try {