This is an automated email from the ASF dual-hosted git repository. shuai pushed a commit to branch feat/1.5.1/table in repository https://gitbox.apache.org/repos/asf/answer.git
commit 5555411db9061882f537253c37e72de96ee0d1bf Author: shuai <lishuail...@sifou.com> AuthorDate: Mon May 19 10:33:24 2025 +0800 feat: Supports separate setting of navigation background color --- i18n/en_US.yaml | 8 +- ui/src/components/Header/index.scss | 2 +- ui/src/components/Header/index.tsx | 12 +- ui/src/pages/Admin/Themes/index.tsx | 24 +- ui/src/stores/themeSetting.ts | 2 +- ui/src/utils/color.ts | 4 + ui/test.html | 463 ------------------------------------ 7 files changed, 39 insertions(+), 476 deletions(-) diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index a22396cf..6bae82b9 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -1927,9 +1927,9 @@ ui: name: Name email: Email reputation: Reputation - created_at: Created Time - delete_at: Deleted Time - suspend_at: Suspended Time + created_at: Created time + delete_at: Deleted time + suspend_at: Suspended time status: Status role: Role action: Action @@ -2143,7 +2143,7 @@ ui: color_scheme: label: Color scheme navbar_style: - label: Navbar style + label: Navbar background style primary_color: label: Primary color text: Modify the colors used by your themes diff --git a/ui/src/components/Header/index.scss b/ui/src/components/Header/index.scss index 0bc6e2e3..1f362dcc 100644 --- a/ui/src/components/Header/index.scss +++ b/ui/src/components/Header/index.scss @@ -63,7 +63,7 @@ } // style for colored navbar - &.theme-colored { + &.theme-dark { .placeholder-search { padding-left: 42px; box-shadow: none; diff --git a/ui/src/components/Header/index.tsx b/ui/src/components/Header/index.tsx index 52bd0922..1003220e 100644 --- a/ui/src/components/Header/index.tsx +++ b/ui/src/components/Header/index.tsx @@ -24,7 +24,7 @@ import { Link, NavLink, useLocation, useMatch } from 'react-router-dom'; import classnames from 'classnames'; -import { userCenter, floppyNavigation } from '@/utils'; +import { userCenter, floppyNavigation, isLight } from '@/utils'; import { loggedUserInfoStore, siteInfoStore, @@ -82,9 +82,12 @@ const Header: FC = () => { }, [location.pathname]); let navbarStyle = 'theme-colored'; + let themeMode = 'light'; const { theme, theme_config } = themeSettingStore((_) => _); if (theme_config?.[theme]?.navbar_style) { - navbarStyle = `theme-${theme_config[theme].navbar_style}`; + themeMode = isLight(theme_config[theme].navbar_style) ? 'light' : 'dark'; + console.log('isLightTheme', themeMode); + navbarStyle = `theme-${themeMode}`; } useEffect(() => { @@ -103,9 +106,12 @@ const Header: FC = () => { return ( <Navbar - variant={navbarStyle === 'theme-colored' ? 'dark' : ''} + data-bs-theme={themeMode} expand="xl" className={classnames('sticky-top', navbarStyle)} + style={{ + backgroundColor: theme_config[theme].navbar_style, + }} id="header"> <div className="w-100 d-flex align-items-center px-3"> <Navbar.Toggle diff --git a/ui/src/pages/Admin/Themes/index.tsx b/ui/src/pages/Admin/Themes/index.tsx index b5dc2ebd..63a49055 100644 --- a/ui/src/pages/Admin/Themes/index.tsx +++ b/ui/src/pages/Admin/Themes/index.tsx @@ -60,9 +60,7 @@ const Index: FC = () => { navbar_style: { type: 'string', title: t('navbar_style.label'), - enum: ['colored', 'light'], - enumNames: ['Colored', 'Light'], - default: 'colored', + default: DEFAULT_THEME_COLOR, }, primary_color: { type: 'string', @@ -80,7 +78,19 @@ const Index: FC = () => { 'ui:widget': 'select', }, navbar_style: { - 'ui:widget': 'select', + 'ui:widget': 'input_group', + 'ui:options': { + inputType: 'color', + suffixBtnOptions: { + text: '', + variant: 'outline-secondary', + iconName: 'arrow-counterclockwise', + actionType: 'click', + title: t('reset', { keyPrefix: 'btns' }), + // eslint-disable-next-line @typescript-eslint/no-use-before-define + clickCallback: () => resetNavbarStyle(), + }, + }, }, primary_color: { 'ui:widget': 'input_group', @@ -102,6 +112,12 @@ const Index: FC = () => { const [formData, setFormData] = useState(initFormData(schema)); const { update: updateThemeSetting } = themeSettingStore((_) => _); + const resetNavbarStyle = () => { + const formMeta = { ...formData }; + formMeta.navbar_style.value = DEFAULT_THEME_COLOR; + setFormData({ ...formMeta }); + }; + const resetPrimaryScheme = () => { const formMeta = { ...formData }; formMeta.primary_color.value = DEFAULT_THEME_COLOR; diff --git a/ui/src/stores/themeSetting.ts b/ui/src/stores/themeSetting.ts index c48d9adf..9f6802b8 100644 --- a/ui/src/stores/themeSetting.ts +++ b/ui/src/stores/themeSetting.ts @@ -36,7 +36,7 @@ const store = create<IType>((set) => ({ theme_options: [{ label: 'Default', value: 'default' }], theme_config: { default: { - navbar_style: 'colored', + navbar_style: DEFAULT_THEME_COLOR, primary_color: DEFAULT_THEME_COLOR, }, }, diff --git a/ui/src/utils/color.ts b/ui/src/utils/color.ts index 52cdfc1d..6aa51564 100644 --- a/ui/src/utils/color.ts +++ b/ui/src/utils/color.ts @@ -60,3 +60,7 @@ export const shiftColor = (color, weight) => { } return tintColor(color, -weight); }; + +export const isLight = (color) => { + return Color(color).isLight(); +}; diff --git a/ui/test.html b/ui/test.html deleted file mode 100644 index 28577a55..00000000 --- a/ui/test.html +++ /dev/null @@ -1,463 +0,0 @@ -<!-- - - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - ---> -<!DOCTYPE html> -<html lang="zh-CN"> - -<head> - <meta charset="utf-8" /> - <title>快速问答</title> - <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" /> - <meta name="theme-color" /> - <meta name="description" content="" data-rh="true" /> - <meta name="generator" content="Answer 1.4.5 - https://github.com/apache/answer version 568f1e9f"> - - - - <link rel="canonical" href="http://localhost" /> - <link rel="manifest" href="/manifest.json" /> - <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="快速问答" /> - <link href="/static/css/main.7900d206.css" rel="stylesheet" /> - <link href="/custom.css" rel="stylesheet" /> - <link rel="icon" type="image/png" href="/favicon.ico" data-rh="true" /> - <link rel="icon" type="image/png" sizes="192x192" href="" data-rh="true" /> - <link rel="apple-touch-icon" type="image/png" href="" data-rh="true" /> - - <script defer="defer" src="/static/js/chunk-mix1.6e509cad.chunk.js"></script> - - <script defer="defer" src="/static/js/chunk-mix2.3ecf665a.chunk.js"></script> - - <script defer="defer" src="/static/js/chunk-mix3.8dafb7ec.chunk.js"></script> - - <script defer="defer" src="/static/js/codemirror.846cdf64.js"></script> - - <script defer="defer" src="/static/js/lezer.85e7351a.js"></script> - - <script defer="defer" src="/static/js/react-dom.90ee5423.chunk.js"></script> - - <script defer="defer" src="/static/js/chunk-nodesInitial.02c0c216.chunk.js"></script> - - <script defer="defer" src="/static/js/main.6fb8e749.js"></script> - - - - <meta property="og:type" content="website" /> - <meta property="og:title" name="twitter:title" content="快速问答" /> - <meta property="og:site_name" content="快速问答" /> - <meta property="og:url" content="http://localhost" /> - <meta property="og:description" content="" /> - <meta property="og:image" itemProp="image primaryImageOfPage" content="/favicon.ico" /> - <meta name="twitter:card" content="summary" /> - <meta name="twitter:domain" content="http://localhost" /> - <meta name="twitter:description" content="" /> - <meta name="twitter:image" content="/favicon.ico" /> - <meta name="go-template"> - - - -</head> - -<body> - - - - <div id="root"> - - <div id="spin-mask"> - <noscript> - <style> - #spin-mask { - display: none !important; - } - - #protect-browser { - display: none; - } - </style> - </noscript> - <style> - @keyframes _doc-spin { - to { - transform: rotate(360deg) - } - } - - #spin-mask { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: white; - z-index: 9999; - } - - #spin-container { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - } - - #spin-container .spinner { - box-sizing: border-box; - display: inline-block; - width: 2rem; - height: 2rem; - vertical-align: -.125em; - border: .25rem solid currentColor; - border-right-color: transparent; - color: rgba(108, 117, 125, .75); - border-radius: 50%; - animation: 0.75s linear infinite _doc-spin; - } - - #protect-browser { - padding: 20px; - text-align: center; - } - </style> - <div id="spin-container"> - <div class="spinner"></div> - </div> - <div id="protect-browser"></div> - </div> - - <nav id="header" class="sticky-top theme-colored navbar navbar-expand-lg navbar-dark"> - <div class="w-100 d-flex align-items-center px-3"> - <button aria-controls="navBarContent" type="button" aria-label="Toggle navigation" - class="answer-navBar me-2 navbar-toggler collapsed"> - <span class="navbar-toggler-icon"></span> - </button> - <div class="d-flex justify-content-between align-items-center nav-grow flex-nowrap"> - - <a class="lh-1 me-0 me-sm-3 navbar-brand" href="/"> - 快速问答 - </a> - - </div> - <div class="d-none d-xl-block flex-grow-1 me-auto"> - <div class="d-none d-xl-block ps-0 col-lg-8"> - <form action="/search" class="w-100 maxw-400"> - <input placeholder="Search" name="q" type="search" class="placeholder-search form-control" value=""> - </form> - </div> - - <div class="d-none d-xl-flex justify-content-start justify-content-sm-end col-lg-4"> - - </div> - </div> - </div> - </nav> - <div class="position-relative page-wrap d-flex flex-column flex-fill"> - <div class="d-flex"> - <div class="position-sticky px-3 border-end pt-4 d-none d-xl-block" id="pcSideNav"> - - <div class="flex-column nav nav-pills"> - <a class="nav-link active" href="/questions"> - <i class="br bi-question-circle-fill me-2"></i> - <span>ui.header.nav.question</span> - </a> - <a href="/tags" data-rr-ui-event-key="/tags" class="nav-link"> - <i class="br bi-tags-fill me-2"></i> - <span>ui.header.nav.tag</span> - </a> - <a class="nav-link" href="/users"> - <i class="br bi-people-fill me-2"></i> - <span>ui.header.nav.user</span> - </a> - <a class="nav-link" href="/badges"> - <i class="br bi-people-fill me-2"></i> - <span>ui.header.nav.badges</span> - </a> - </div> - - </div> - <div class="flex-fill w-100"> - - <div class="d-flex justify-content-center px-0 px-md-4"> - <div class="pt-4 mb-5 row"> - <div class="page-main flex-auto col"> - <div> - <div class="mb-3 d-flex flex-wrap justify-content-between"> - <h5 class="fs-5 text-nowrap mb-3 mb-md-0"> - ui.question.all_questions - </h5> - - <div role="group" class="md-show me-2 btn-group btn-group-sm"> - <a role="button" tabindex="0" href="?order=newest" - class="text-capitalize fit-content btn active btn-outline-secondary"> - ui.question.newest - </a> - <a role="button" tabindex="0" href="?order=active" - class="text-capitalize fit-content btn btn-outline-secondary"> - ui.question.active - </a> - - <a role="button" tabindex="0" href="?order=unanswered" - class="text-capitalize fit-content d-none d-md-block btn btn-outline-secondary" - style="border-top-right-radius: 0.25rem; border-bottom-right-radius: 0.25rem;"> - ui.question.unanswered - </a> - <a role="button" tabindex="0" href="?order=frequent" - class="text-capitalize fit-content d-none d-md-block btn btn-outline-secondary" - style="border-top-right-radius: 0.25rem; border-bottom-right-radius: 0.25rem;"> - ui.question.frequent - </a> - <div role="group" class="show dropdown btn-group"> - <button type="button" aria-expanded="true" - class="dropdown-toggle show btn btn-outline-secondary btn-sm"> - ui.btns.more - </button> - <div x-placement="bottom-start" class="dropdown-menu show" data-popper-reference-hidden="false" - data-popper-escaped="false" data-popper-placement="bottom-start" - style="position: absolute; inset: 0px auto auto 0px; transform: translate(0px, 33px);"> - <a href="?order=score" aria-selected="false" class="text-capitalize dropdown-item"> - ui.question.score</a> - </div> - </div> - </div> - - <div class="dropdown"> - <button type="button" id="react-aria8245013726-:r5:" aria-expanded="false" - class="dropdown-toggle btn btn-outline-secondary btn-sm"><i - class="br bi-view-stacked"></i></button> - <div x-placement="bottom-end" aria-labelledby="react-aria8245013726-:r5:" - class="dropdown-menu dropdown-menu-end" data-popper-reference-hidden="false" - data-popper-escaped="false" data-popper-placement="bottom-end" - style="position: absolute; inset: 0px 0px auto auto; transform: translate(0px, 33px);"> - <div class="dropdown-header" role="heading"> - ui.btns.view - </div> - <a aria-selected="true" data-rr-ui-dropdown-item="" class="dropdown-item active" role="button" - tabindex="0" href="#" data-footnote-fixed="true"> - ui.btns.card - </a> - <a aria-selected="false" data-rr-ui-dropdown-item="" class="dropdown-item" role="button" - tabindex="0" href="#" data-footnote-fixed="true"> - ui.btns.compact - </a> - </div> - </div> - - </div> - <div class="rounded-0 list-group"> - - <li - class="py-3 px-2 border-start-0 border-end-0 position-relative pointer list-group-item list-group-item-action"> - <div class="d-flex flex-wrap text-secondary small mb-12"> - <div class="d-flex align-items-center text-secondary me-1"> - <a href="/users/shuai"> - <img - src="/users/https://www.gravatar.com/avatar/862c8fcfd7e97b5c399e65cb1b99b20244d958c5ee1a8a5193e274df6de16262" - width="24px" height="24px" class="rounded-circle me-1" alt="shuai" data-processed="true"> - <span class="me-1 name-ellipsis" style="max-width: 300px;">shuai</span> - </a> - <span class="fw-bold" title="Reputation">1</span> - </div> - • - <time class="text-secondary ms-1" datetime="2025-02-24T16:44:41.000Z" - title="ui.dpmte41.long_dpmte_wit4_ti44e"> - ui.question.asked - ui.dpmte41.long_dpmte - </time> - </div> - - <h5 class="text-wrap text-break"> - - <a class="link-dark d-block" href="/questions/10010000000000002">What is a tag?</a> - - </h5> - - <div class="text-truncate-2 mb-2"> - - <a class="d-block small text-body" href="/questions/10010000000000002">When asking a question, - we need to choose tags. What are tags and why should I use them?</a> - - </div> - - <div class="question-tags mb-12"> - - <a href="/tags/support" class="badge-tag rounded-1 me-1"> - <span class="">support</span> - </a> - - </div> - - <div class="small text-secondary"> - <div class="d-flex align-items-center mt-2 mt-md-0"> - <div class="d-flex align-items-center flex-shrink-0"> - <i class="br bi-hand-thumbs-up-fill me-1"></i> - <span class="fw-medium">0</span> - <span class="ms-1">ui.counts.votes</span> - </div> - <div class="d-flex flex-shrink-0 align-items-center ms-3"> - <i class="br bi-chat-square-text-fill me-1"></i> - <span class="fw-medium">1</span> - <span class="ms-1">ui.counts.answers</span> - </div> - <span class="summary-stat ms-3 flex-shrink-0"> - <i class="br bi-bar-chart-fill"></i> - <span class="fw-medium ms-1">0</span> - <span class="ms-1">ui.counts.views</span> - </span> - </div> - </div> - </li> - - <li - class="py-3 px-2 border-start-0 border-end-0 position-relative pointer list-group-item list-group-item-action"> - <div class="d-flex flex-wrap text-secondary small mb-12"> - <div class="d-flex align-items-center text-secondary me-1"> - <a href="/users/shuai"> - <img - src="/users/https://www.gravatar.com/avatar/862c8fcfd7e97b5c399e65cb1b99b20244d958c5ee1a8a5193e274df6de16262" - width="24px" height="24px" class="rounded-circle me-1" alt="shuai" data-processed="true"> - <span class="me-1 name-ellipsis" style="max-width: 300px;">shuai</span> - </a> - <span class="fw-bold" title="Reputation">1</span> - </div> - • - <time class="text-secondary ms-1" datetime="2025-02-24T16:44:41.000Z" - title="ui.dpmte41.long_dpmte_wit4_ti44e"> - ui.question.asked - ui.dpmte41.long_dpmte - </time> - </div> - - <h5 class="text-wrap text-break"> - - <a class="link-dark d-block" href="/questions/10010000000000004">What is reputation and how do I - earn them?</a> - - </h5> - - <div class="text-truncate-2 mb-2"> - - <a class="d-block small text-body" href="/questions/10010000000000004">I see that each user has - reputation points, What is it and how do I earn them?</a> - - </div> - - <div class="question-tags mb-12"> - - <a href="/tags/support" class="badge-tag rounded-1 me-1"> - <span class="">support</span> - </a> - - </div> - - <div class="small text-secondary"> - <div class="d-flex align-items-center mt-2 mt-md-0"> - <div class="d-flex align-items-center flex-shrink-0"> - <i class="br bi-hand-thumbs-up-fill me-1"></i> - <span class="fw-medium">0</span> - <span class="ms-1">ui.counts.votes</span> - </div> - <div class="d-flex flex-shrink-0 align-items-center ms-3"> - <i class="br bi-chat-square-text-fill me-1"></i> - <span class="fw-medium">1</span> - <span class="ms-1">ui.counts.answers</span> - </div> - <span class="summary-stat ms-3 flex-shrink-0"> - <i class="br bi-bar-chart-fill"></i> - <span class="fw-medium ms-1">0</span> - <span class="ms-1">ui.counts.views</span> - </span> - </div> - </div> - </li> - - </div> - <div class="mt-4 mb-2 d-flex justify-content-center"> - - <ul class="d-inline-flex mb-0 pagination pagination-sm"> - - - - <li class="page-item active"> - <span class="page-link" href="questions?page=1">1 - <span class="visually-hidden">(current)</span> - </span> - </li> - - - - </ul> - - </div> - </div> - </div> - <div class="page-right-side mt-4 mt-xl-0 col"> - - <div class="card"> - <div class="text-nowrap text-capitalize card-header">ui.question.hot_questions</div> - <div class="list-group list-group-flush"> - - - <a class="list-group-item list-group-item-action" href="/questions/10010000000000002"> - - <div class="link-dark">What is a tag?</div> - - <div class="d-flex align-items-center small mt-1 link-secondary"> - <i class="br bi-chat-square-text-fill"></i> - <span class="ms-1">ui.question.x_answers</span> - </div> - - </a> - - - <a class="list-group-item list-group-item-action" href="/questions/10010000000000004"> - - <div class="link-dark">What is reputation and how do I earn them?</div> - - <div class="d-flex align-items-center small mt-1 link-secondary"> - <i class="br bi-chat-square-text-fill"></i> - <span class="ms-1">ui.question.x_answers</span> - </div> - - </a> - - </div> - </div> - - </div> - </div> - </div> - - <footer class="py-3 bg-light w-100"> - <p class="text-center mb-0 small"> - <a class="me-3" href="/tos" data-discover="true"> - ui.admin.legal.terms_of_service.label - </a> - <a href="/privacy" data-discover="true"> - ui.admin.legal.privacy_policy.label - </a> - </p> - <p class="text-center mb-0 small text-secondary"> - ui.footer.build_on - </p> - </footer> - </div> - </div> - </div> - </div> -</body> -</html> \ No newline at end of file