This is an automated email from the ASF dual-hosted git repository.

jiekaichang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/mahout.git

commit 6449693b56d5cbeb69cfca63b82c83e1cc154b8f
Author: 400Ping <[email protected]>
AuthorDate: Tue Jan 27 19:33:22 2026 +0800

    [Docs] Switch Icon#954
---
 docs/blog/authors.yml                              |   3 +-
 website/src/theme/Blog/Components/Author/index.tsx | 126 +++++++++++++++++++++
 .../theme/Blog/Components/Author/styles.module.css |  67 +++++++++++
 website/static/img/mahout-favicon-black.svg        |  10 ++
 website/static/img/mahout-icon-black.svg           |  40 +++++++
 5 files changed, 245 insertions(+), 1 deletion(-)

diff --git a/docs/blog/authors.yml b/docs/blog/authors.yml
index 8e4ab6811..f0093add3 100644
--- a/docs/blog/authors.yml
+++ b/docs/blog/authors.yml
@@ -2,4 +2,5 @@ mahout-team:
   name: Mahout Team
   title: Apache Mahout
   url: https://mahout.apache.org
-  image_url: /img/mahout-logo-blue.svg
+  image_url: /img/mahout-favicon-black.svg
+  image_url_dark: /img/mahout-favicon.svg
diff --git a/website/src/theme/Blog/Components/Author/index.tsx 
b/website/src/theme/Blog/Components/Author/index.tsx
new file mode 100644
index 000000000..e327f48d6
--- /dev/null
+++ b/website/src/theme/Blog/Components/Author/index.tsx
@@ -0,0 +1,126 @@
+import React, {type ReactNode} from 'react';
+import clsx from 'clsx';
+import Link, {type Props as LinkProps} from '@docusaurus/Link';
+import useBaseUrl from '@docusaurus/useBaseUrl';
+import ThemedImage from '@theme/ThemedImage';
+import AuthorSocials from '@theme/Blog/Components/Author/Socials';
+import type {Props} from '@theme/Blog/Components/Author';
+import Heading from '@theme/Heading';
+import styles from './styles.module.css';
+
+type AuthorImageVariants = {
+  imageURLDark?: string;
+  image_url_dark?: string;
+};
+
+function getAuthorImageURLDark(author: Props['author']): string | undefined {
+  const authorWithDark = author as Props['author'] & AuthorImageVariants;
+  return authorWithDark.imageURLDark ?? authorWithDark.image_url_dark;
+}
+
+function MaybeLink(props: LinkProps): ReactNode {
+  if (props.href) {
+    return <Link {...props} />;
+  }
+  return <>{props.children}</>;
+}
+
+function AuthorTitle({title}: {title: string}) {
+  return (
+    <small className={styles.authorTitle} title={title}>
+      {title}
+    </small>
+  );
+}
+
+function AuthorName({name, as}: {name: string; as: Props['as']}) {
+  if (!as) {
+    return (
+      <span className={styles.authorName} translate="no">
+        {name}
+      </span>
+    );
+  } else {
+    return (
+      <Heading as={as} className={styles.authorName} translate="no">
+        {name}
+      </Heading>
+    );
+  }
+}
+
+function AuthorBlogPostCount({count}: {count: number}) {
+  return <span className={clsx(styles.authorBlogPostCount)}>{count}</span>;
+}
+
+// Note: in the future we might want to have multiple "BlogAuthor" components
+// Creating different display modes with the "as" prop may not be the best idea
+// Explainer: https://kyleshevlin.com/prefer-multiple-compositions/
+// For now, we almost use the same design for all cases, so it's good enough
+export default function BlogAuthor({
+  as,
+  author,
+  className,
+  count,
+}: Props): ReactNode {
+  const {name, title, url, imageURL: imageURLRaw, email, page} = author;
+  const link =
+    page?.permalink || url || (email && `mailto:${email}`) || undefined;
+  const imageURL = imageURLRaw ? useBaseUrl(imageURLRaw) : undefined;
+  const imageURLDarkRaw = getAuthorImageURLDark(author);
+  const imageURLDark = imageURLDarkRaw ? useBaseUrl(imageURLDarkRaw) : 
undefined;
+
+  const image = imageURL ? (
+    imageURLDark ? (
+      <ThemedImage
+        className={clsx('avatar__photo', styles.authorImage)}
+        sources={{
+          light: imageURL,
+          dark: imageURLDark,
+        }}
+        alt={name}
+      />
+    ) : (
+      <img
+        className={clsx('avatar__photo', styles.authorImage)}
+        src={imageURL}
+        alt={name}
+      />
+    )
+  ) : null;
+
+  return (
+    <div
+      className={clsx(
+        'avatar margin-bottom--sm',
+        className,
+        styles[`author-as-${as}`],
+      )}>
+      {image && (
+        <MaybeLink href={link} className="avatar__photo-link">
+          {image}
+        </MaybeLink>
+      )}
+
+      {(name || title) && (
+        <div className={clsx('avatar__intro', styles.authorDetails)}>
+          <div className="avatar__name">
+            {name && (
+              <MaybeLink href={link}>
+                <AuthorName name={name} as={as} />
+              </MaybeLink>
+            )}
+            {count !== undefined && <AuthorBlogPostCount count={count} />}
+          </div>
+          {!!title && <AuthorTitle title={title} />}
+
+          {/*
+            We always render AuthorSocials even if there's none
+            This keeps other things aligned with flexbox layout
+          */}
+          <AuthorSocials author={author} />
+        </div>
+      )}
+    </div>
+  );
+}
diff --git a/website/src/theme/Blog/Components/Author/styles.module.css 
b/website/src/theme/Blog/Components/Author/styles.module.css
new file mode 100644
index 000000000..506bc5b36
--- /dev/null
+++ b/website/src/theme/Blog/Components/Author/styles.module.css
@@ -0,0 +1,67 @@
+.authorImage {
+  --ifm-avatar-photo-size: 3.6rem;
+}
+
+.author-as-h1 .authorImage {
+  --ifm-avatar-photo-size: 7rem;
+}
+
+.author-as-h2 .authorImage {
+  --ifm-avatar-photo-size: 5.4rem;
+}
+
+.authorDetails {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-start;
+  justify-content: space-around;
+}
+
+.authorName {
+  font-size: 1.1rem;
+  line-height: 1.1rem;
+  display: flex;
+  flex-direction: row;
+}
+
+.author-as-h1 .authorName {
+  font-size: 2.4rem;
+  line-height: 2.4rem;
+  display: inline;
+}
+
+.author-as-h2 .authorName {
+  font-size: 1.4rem;
+  line-height: 1.4rem;
+  display: inline;
+}
+
+.authorTitle {
+  font-size: 0.8rem;
+  line-height: 1rem;
+  display: -webkit-box;
+  overflow: hidden;
+  line-clamp: 1;
+  -webkit-line-clamp: 1;
+  -webkit-box-orient: vertical;
+}
+
+.author-as-h1 .authorTitle {
+  font-size: 1.2rem;
+  line-height: 1.6rem;
+}
+
+.author-as-h2 .authorTitle {
+  font-size: 1rem;
+  line-height: 1.3rem;
+}
+
+.authorBlogPostCount {
+  background: var(--ifm-color-secondary);
+  color: var(--ifm-color-black);
+  font-size: 0.8rem;
+  line-height: 1.2;
+  border-radius: var(--ifm-global-radius);
+  padding: 0.1rem 0.4rem;
+  margin-left: 0.3rem;
+}
diff --git a/website/static/img/mahout-favicon-black.svg 
b/website/static/img/mahout-favicon-black.svg
new file mode 100644
index 000000000..e862602df
--- /dev/null
+++ b/website/static/img/mahout-favicon-black.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg
+  width="180"
+  height="180"
+  viewBox="0 0 180 180"
+  xmlns="http://www.w3.org/2000/svg";>
+  <g transform="translate(16 0)" fill="#000000">
+    <path 
d="M71,148.3v-18.6c-7.4-1.4-13-7.9-13-15.7c0-3.2,1-6.3,2.6-8.8L45,93.7l-15.6,11.5c1.7,2.5,2.6,5.5,2.6,8.8c0,3.3-1,6.3-2.7,8.8l35.5,28C66.7,149.6,68.8,148.7,71,148.3z
 
M77,148.3c2.2,0.4,4.3,1.3,6.1,2.6l35.5-28c-1.7-2.5-2.7-5.6-2.7-8.8c0-3.2,1-6.3,2.6-8.8L103,93.7l-15.6,11.5c1.7,2.5,2.6,5.5,2.6,8.8c0,7.8-5.6,14.3-13,15.7V148.3z
 
M87.3,155.2c1.7,2.5,2.7,5.6,2.7,8.8c0,8.8-7.2,16-16,16s-16-7.2-16-16c0-3.3,1-6.3,2.7-8.8l-35.5-28c-2.6,1.8-5.7,2.9-9.1,2.9c-8.8,0-16-7.2-16-16c0-7.8,5.6-14
 [...]
+  </g>
+</svg>
diff --git a/website/static/img/mahout-icon-black.svg 
b/website/static/img/mahout-icon-black.svg
new file mode 100644
index 000000000..d206f56db
--- /dev/null
+++ b/website/static/img/mahout-icon-black.svg
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg"; x="0px" y="0px" 
viewBox="0 0 148 180">
+<style type="text/css">.st0{fill:#000000;}</style>
+<g>
+       <path class="st0" 
d="M71,148.3v-18.6c-7.4-1.4-13-7.9-13-15.7c0-3.2,1-6.3,2.6-8.8L45,93.7l-15.6,11.5c1.7,2.5,2.6,5.5,2.6,8.8
+               c0,3.3-1,6.3-2.7,8.8l35.5,28C66.7,149.6,68.8,148.7,71,148.3z 
M77,148.3c2.2,0.4,4.3,1.3,6.1,2.6l35.5-28
+               
c-1.7-2.5-2.7-5.6-2.7-8.8c0-3.2,1-6.3,2.6-8.8L103,93.7l-15.6,11.5c1.7,2.5,2.6,5.5,2.6,8.8c0,7.8-5.6,14.3-13,15.7V148.3z
+                
M87.3,155.2c1.7,2.5,2.7,5.6,2.7,8.8c0,8.8-7.2,16-16,16s-16-7.2-16-16c0-3.3,1-6.3,2.7-8.8l-35.5-28c-2.6,1.8-5.7,2.9-9.1,2.9
+               
c-8.8,0-16-7.2-16-16c0-7.8,5.6-14.3,13-15.7V81.7C5.6,80.3,0,73.8,0,66c0-8.8,7.2-16,16-16c3.4,0,6.5,1.1,9.1,2.9l35.5-28
+               
C59,22.3,58,19.3,58,16c0-8.8,7.2-16,16-16s16,7.2,16,16c0,3.3-1,6.3-2.7,8.8l35.5,28c2.6-1.8,5.7-2.9,9.1-2.9c8.8,0,16,7.2,16,16
+               
c0,7.8-5.6,14.3-13,15.7v16.6c7.4,1.4,13,7.9,13,15.7c0,8.8-7.2,16-16,16c-3.4,0-6.5-1.1-9.1-2.9L87.3,155.2z
 M25.2,100.9L39.9,90
+               
L25.2,79.1c-1.8,1.3-3.9,2.2-6.2,2.6v16.6C21.3,98.7,23.4,99.6,25.2,100.9z 
M29.4,74.8L45,86.3l15.6-11.5C59,72.3,58,69.2,58,66
+               
c0-7.8,5.6-14.3,13-15.7V31.7c-2.2-0.4-4.3-1.3-6.1-2.6l-35.5,28C31,59.7,32,62.7,32,66C32,69.2,31,72.3,29.4,74.8z
 M122.8,100.9
+               
c1.8-1.3,3.9-2.2,6.2-2.6V81.7c-2.3-0.4-4.4-1.3-6.2-2.6L108.1,90L122.8,100.9z 
M118.7,57.2l-35.5-28c-1.8,1.3-3.9,2.2-6.1,2.6
+               
v18.6c7.4,1.4,13,7.9,13,15.7c0,3.2-1,6.3-2.6,8.8L103,86.3l15.6-11.5c-1.7-2.5-2.6-5.5-2.6-8.8C116,62.7,117,59.7,118.7,57.2z
+                
M64.8,100.9c2.6-1.8,5.8-2.9,9.2-2.9s6.6,1.1,9.2,2.9L97.9,90L83.2,79.1C80.6,80.9,77.4,82,74,82s-6.6-1.1-9.2-2.9L50.1,90
+               L64.8,100.9z 
M74,76c5.5,0,10-4.5,10-10s-4.5-10-10-10s-10,4.5-10,10S68.5,76,74,76z 
M74,124c5.5,0,10-4.5,10-10
+               c0-5.5-4.5-10-10-10s-10,4.5-10,10C64,119.5,68.5,124,74,124z 
M132,76c5.5,0,10-4.5,10-10s-4.5-10-10-10s-10,4.5-10,10
+               S126.5,76,132,76z 
M132,124c5.5,0,10-4.5,10-10c0-5.5-4.5-10-10-10s-10,4.5-10,10C122,119.5,126.5,124,132,124z
 M16,76
+               c5.5,0,10-4.5,10-10s-4.5-10-10-10S6,60.5,6,66S10.5,76,16,76z 
M16,124c5.5,0,10-4.5,10-10c0-5.5-4.5-10-10-10s-10,4.5-10,10
+               C6,119.5,10.5,124,16,124z 
M74,174c5.5,0,10-4.5,10-10s-4.5-10-10-10s-10,4.5-10,10S68.5,174,74,174z 
M74,26c5.5,0,10-4.5,10-10
+               S79.5,6,74,6s-10,4.5-10,10S68.5,26,74,26z"/>
+</g>
+</svg>

Reply via email to