Copilot commented on code in PR #1964:
URL: https://github.com/apache/apisix-website/pull/1964#discussion_r2807188599


##########
website/src/css/customTheme.scss:
##########
@@ -322,18 +583,6 @@ a:hover {
     padding-right: 20px;
   }
 

Review Comment:
   The media query at line 514-585 modifies `.hero-sec-wrap` to use `display: 
flex !important` (line 515) and sets `height: 100vh !important` (line 516), 
while also modifying the `.homeCanvas` to have `opacity: 0.2 !important` (line 
539). However, this media query appears to be for desktop/larger screens (based 
on surrounding context), not mobile.
   
   This contradicts the changes in `hero.scss` which already define extensive 
responsive behavior for the hero section. Having conflicting or overlapping 
hero section styles in two different SCSS files (customTheme.scss and 
hero.scss) creates confusion and makes it difficult to understand which styles 
apply at which breakpoints. Consider consolidating all hero section responsive 
styles into a single location.



##########
website/src/components/sections/Architecture.tsx:
##########
@@ -42,10 +42,10 @@ const Architecture: FC = () => (
       </div>
       <div className="arch-card-caption">
         <p>
-          <Translate id="architecture.component.card.caption">
-            Apache APISIX is based on NGINX and etcd. Compared with 
traditional API Gateways, APISIX
-            has features like dynamic routing and hot-loading plugins, etc.
-          </Translate>
+          Apache APISIX is based on NGINX and etcd.
+          Compared with traditional API Gateways,
+          APISIX has features like dynamic routing<br />
+          and hot-loading plugins, etc.

Review Comment:
   Replacing the Translate component with hardcoded English text breaks 
internationalization (i18n) support. The original code used:
   ```
   <Translate id="architecture.component.card.caption">
     Apache APISIX is based on NGINX and etcd. Compared with traditional API 
Gateways, APISIX has features like dynamic routing and hot-loading plugins, etc.
   </Translate>
   ```
   
   The new hardcoded text will not be translatable and will always display in 
English regardless of the user's language preference. Additionally, the manual 
line break with `<br />` tag disrupts the natural text flow that would be 
handled by CSS word-wrapping. If this change was intentional to fix a layout 
issue, it should be done through CSS, not by breaking i18n functionality.
   ```suggestion
             <Translate id="architecture.component.card.caption">
               Apache APISIX is based on NGINX and etcd. Compared with 
traditional API Gateways, APISIX has features like dynamic routing and 
hot-loading plugins, etc.
             </Translate>
   ```



##########
website/src/css/landing-sections/hero.scss:
##########
@@ -158,3 +312,339 @@
     width: 40vw;
   }
 }
+
+@media (max-width: 996px) {
+  .hero-sec-wrap {
+    display: block !important;
+    height: 100vh !important;
+    min-height: 100vh;
+  }
+
+  .hero-text {
+    width: 90%;
+    max-width: 800px;
+    padding: 40px 30px;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    text-align: center;
+  }
+
+  .hero-title {
+    width: 100%;
+    max-width: 100%;
+    font-size: 3rem;
+  }
+
+  .hero-title::after {
+    width: 60px;
+    left: 50%;
+    transform: translateX(-50%);
+  }
+
+  .hero-subtitle {
+    width: 100%;
+    padding-right: 0;
+  }
+
+  .homeCanvas {
+    width: 100% !important;
+    height: 100% !important;
+    opacity: 0.85 !important;
+  }
+
+  .hero-ctas {
+    justify-content: center;
+    gap: 15px;
+  }
+}
+
+@media (max-width: 768px) {
+  .hero-text {
+    width: 95%;
+    max-width: 600px;
+    padding: 30px 25px;
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+  }
+
+  .hero-title {
+    font-size: 2.5rem;
+    max-width: 100%;
+  }
+
+  .hero-subtitle {
+    font-size: 1rem;
+  }
+
+  .btn {
+    padding: 16px 32px;
+    font-size: 1.1rem;
+  }
+}

Review Comment:
   Multiple media queries targeting the same breakpoint (max-width: 768px) are 
defined separately instead of being consolidated. This appears at:
   - Line 287 for features
   - Line 363 for hero section 
   - Line 389 for another hero section block
   
   Consolidating styles for the same breakpoint into a single media query block 
improves maintainability and makes it easier to understand all responsive 
changes for a given viewport size.



##########
website/src/css/landing-sections/hero.scss:
##########
@@ -12,6 +12,35 @@
   }
 }
 
+@keyframes float {
+  0%, 100% {
+    transform: translateY(0px);
+  }
+  50% {
+    transform: translateY(-10px);
+  }
+}
+
+@keyframes pulse {
+  0%, 100% {
+    opacity: 1;
+    transform: scale(1);
+  }
+  50% {
+    opacity: 0.8;
+    transform: scale(1.05);
+  }
+}
+
+@keyframes glow {
+  0%, 100% {
+    box-shadow: 0 0 20px rgba(102, 126, 234, 0.3);
+  }
+  50% {
+    box-shadow: 0 0 40px rgba(102, 126, 234, 0.6);
+  }
+}

Review Comment:
   The PR description states this change fixes "plugin icons rendering and 
responsiveness on Plugins Page." However, the majority of the changes in this 
PR are extensive visual redesigns of the hero section, navbar, features, 
architecture, and other landing page sections that go far beyond plugin icon 
fixes.
   
   The changes include:
   - Complete redesign of hero section with new animations (float, pulse, glow)
   - Full navbar styling overhaul with glassmorphic effects
   - Extensive responsive breakpoints for multiple sections
   - New color schemes and text shadows throughout
   - Button redesigns and hover effects
   
   While these may be improvements, they represent a significant scope 
expansion beyond the stated purpose of fixing plugin icon rendering issues. 
This makes the PR difficult to review and increases risk, as it combines bug 
fixes with substantial visual redesign work.



##########
website/src/css/landing-sections/endcta.module.scss:
##########
@@ -42,6 +42,82 @@ $apisix-color: #e8433e;
 
   & .links {
     display: flex;
+    
+    :global(.btn-download) {
+      background: #030c16;
+      border-style: solid;
+      border-width: 1px;
+      border: none;
+      color: white;
+      padding: 5px 20px;
+      border-radius: 20px;
+      font-size: 1rem;
+      text-decoration: none;
+      margin: 0 10px 0 0;
+      transition: all 0.3s;
+      box-shadow: none;
+      
+      &:hover {
+        background: #000000;
+        color: white;
+        text-decoration: none;
+        box-shadow: 0 4px 12px rgba(244, 89, 89, 0.4);
+      }
+    }
+    
+    :global(.btn-docs) {
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+      
+      &:hover {
+        text-decoration: none;
+      }
+      
+      :global(.goto) {
+        color: #000;
+        text-shadow: none;
+      }
+      
+      &:hover :global(.goto),
+      &:active :global(.goto) {
+        opacity: 0.8;
+        text-shadow: none;
+      }
+      
+      :global(.arrow) {
+        width: 30px;
+        height: 30px;
+        position: relative;
+        
+        svg {
+          position: absolute;
+          top: 50%;
+          left: 50%;
+          transform: translate(-50%, -50%);
+        }
+        
+        polygon,
+        rect {
+          transition: all 250ms;
+        }
+        
+        rect {
+          opacity: 0;
+        }
+      }
+      
+      &:hover :global(.arrow) {
+        polygon {
+          transform: translateX(100px);
+        }
+        
+        rect {
+          transform: translateX(240px);
+          opacity: 1;
+        }
+      }

Review Comment:
   The new styles for `.btn-download` and `.btn-docs` within the `.links` 
section duplicate button styles that are already defined in `hero.scss`. This 
creates style duplication and potential inconsistencies. For example:
   - Button backgrounds, borders, and hover effects are redefined
   - Arrow animations are redefined
   - Transitions are redefined
   
   If these buttons should have different styles in different sections, 
consider using CSS variables or a shared button mixin. If they should be the 
same, reference the global button styles instead of duplicating them. This 
duplication makes it harder to maintain consistent button styling across the 
site.
   ```suggestion
   
   ```



##########
website/src/css/landing-sections/architecture.scss:
##########
@@ -113,6 +121,83 @@
   .docs-promo-subtitle,
   .oss-promo-subtitle {
     left: 7%;
-    width: 85%;
+    width: 80%;
+    max-width: 80%;
+    padding-right: 13%;
+    box-sizing: border-box;
+    word-wrap: break-word;
+    overflow-wrap: break-word;
+    hyphens: auto;
+    line-height: 1.5;
+  }
+  
+  .arch-card-caption > p {
+    width: 95%;
+    font-size: 0.9rem;
+    padding: 5px;
+  }
+}
+
+/* Medium tablets and large phones */
+@media (max-width: 768px) {
+  .arch-card-caption > p {
+    width: 92%;
+    font-size: 0.85rem;
+    padding: 6px;
+    line-height: 1.5;
+  }
+}
+
+@media (max-width: 480px) {
+  .arch-card-border {
+    width: 85% !important;
+    left: 7.5% !important;
+    height: 110% !important;
+  }
+  
+  .arch-card-caption {
+    padding: 0 10px;
+    overflow: hidden;
+    width: 100%;
+    max-width: 100%;
+    box-sizing: border-box;
+  }
+  
+  .arch-card-caption > p {
+    font-size: 0.65rem;
+    width: 80%;
+    max-width: 80%;
+    padding: 8px 0;
+    margin: 15px 0;
+    word-wrap: break-word !important;
+    overflow-wrap: break-word !important;
+    word-break: break-word !important;
+    hyphens: auto;
+    line-height: 1.4;
+    box-sizing: border-box;
+    overflow: hidden;
+  }
+}
+
+/* Extra small devices */
+@media (max-width: 360px) {
+  .arch-card-border {
+    width: 90% !important;
+    left: 5% !important;
+    height: 115% !important;
+  }
+  
+  .arch-card-caption {
+    padding: 0 8px;
+  }
+  
+  .arch-card-caption > p {
+    font-size: 0.6rem;
+    width: 75%;
+    max-width: 75%;
+    word-break: break-all !important;

Review Comment:
   The media query at line 183 targets extremely small devices (max-width: 
360px) and uses `word-break: break-all !important` (line 198). This CSS 
property breaks words at arbitrary character boundaries, which can make text 
very difficult to read by splitting words in unnatural places (e.g., "APISIX" 
could become "API\nSIX").
   
   Consider using `word-break: break-word` instead, which breaks at word 
boundaries when possible and only breaks within words when absolutely 
necessary. This provides better readability while still preventing overflow 
issues.
   ```suggestion
       word-break: break-word !important;
   ```



##########
website/src/pages/plugins.tsx:
##########
@@ -204,15 +204,19 @@ const Plugins: FC = () => {
       return (
         <div key={plugin.name}>
           <PluginCard href={plugin.beta ? 
`/docs/apisix/next/plugins/${pluginUrl}` : `/docs/apisix/plugins/${pluginUrl}`} 
target="_blank">
+
             <PluginIcon>
-              {plugin.useDefaultIcon
-                ? <img className="plugin-logo shadow default" 
src="/img/plugin/default-icon.png" alt={plugin.name} />
-                : (
+              {['batch-requests', 'grpc-transcode', 'error-log-logger', 
'proxy-cache', 'http-logger', 'proxy-mirror', 'proxy-rewrite', 
'response-rewrite', 'request-id', 'tcp-logger', 'zipkin', 'udp-logger', 
'sls-logger', 'syslog', 'limit-conn', 'api-breaker', 'consumer-restriction', 
'basic-auth', 'fault-injection', 'ip-restriction', 'hmac-auth', 'key-auth', 
'limit-count', 'cors', 'limit-req', 'traffic-split', 'request-validation', 
'referer-restriction', 'wolf-rbac', 'jwt-auth', 'authz-casbin', 
'authz-keycloak', 'kafka-logger', 'openid-connect', 'prometheus', 'skywalking', 
'datadog', 'google-cloud-logging', 'uri-blocker', 'redirect', 'echo', 'gzip', 
'real-ip', 'server-info', 'grpc-web', 'mocking', 'authz-casdoor', 'cas-auth', 
'ldap-auth', 'opa', 'forward-auth', 'ext-plugin-pre-req', 
'ext-plugin-post-req', 'ext-plugin-post-resp', 'ua-restriction', 'csrf', 
'public-api', 'node-status', 'opentelemetry', 'skywalking-loggerr', 
'rocketmq-logger', 'clickhouse-logger', 'log-rotate', 'splunk-h
 ec-logging', 'file-logger', 'loggly', 'elasticsearch-logger', 
'tencent-cloud-cls', 'serverless', 'azure-functions', 'openwhisk', 
'aws-lambda', 'workflow', 'openfunction', 'dubbo-proxy', 'mqtt-proxy', 
'kafka-proxy', 'proxy-control', 'client-control', 'CSRF'].includes(plugin.name)

Review Comment:
   The long hardcoded array of 95+ plugin names spanning a single line makes 
the code difficult to read, maintain, and review. This list should be:
   1. Extracted to a constant at the module level for better maintainability
   2. Formatted with proper line breaks for readability
   3. Ideally replaced with the original metadata-driven approach using 
`plugin.useDefaultIcon`
   
   Hardcoding plugin names means this list must be manually updated whenever 
plugins are added, removed, or renamed, increasing maintenance burden and the 
risk of errors.



##########
website/src/pages/plugins.tsx:
##########
@@ -204,15 +204,19 @@ const Plugins: FC = () => {
       return (
         <div key={plugin.name}>
           <PluginCard href={plugin.beta ? 
`/docs/apisix/next/plugins/${pluginUrl}` : `/docs/apisix/plugins/${pluginUrl}`} 
target="_blank">
+
             <PluginIcon>
-              {plugin.useDefaultIcon
-                ? <img className="plugin-logo shadow default" 
src="/img/plugin/default-icon.png" alt={plugin.name} />
-                : (
+              {['batch-requests', 'grpc-transcode', 'error-log-logger', 
'proxy-cache', 'http-logger', 'proxy-mirror', 'proxy-rewrite', 
'response-rewrite', 'request-id', 'tcp-logger', 'zipkin', 'udp-logger', 
'sls-logger', 'syslog', 'limit-conn', 'api-breaker', 'consumer-restriction', 
'basic-auth', 'fault-injection', 'ip-restriction', 'hmac-auth', 'key-auth', 
'limit-count', 'cors', 'limit-req', 'traffic-split', 'request-validation', 
'referer-restriction', 'wolf-rbac', 'jwt-auth', 'authz-casbin', 
'authz-keycloak', 'kafka-logger', 'openid-connect', 'prometheus', 'skywalking', 
'datadog', 'google-cloud-logging', 'uri-blocker', 'redirect', 'echo', 'gzip', 
'real-ip', 'server-info', 'grpc-web', 'mocking', 'authz-casdoor', 'cas-auth', 
'ldap-auth', 'opa', 'forward-auth', 'ext-plugin-pre-req', 
'ext-plugin-post-req', 'ext-plugin-post-resp', 'ua-restriction', 'csrf', 
'public-api', 'node-status', 'opentelemetry', 'skywalking-loggerr', 
'rocketmq-logger', 'clickhouse-logger', 'log-rotate', 'splunk-h
 ec-logging', 'file-logger', 'loggly', 'elasticsearch-logger', 
'tencent-cloud-cls', 'serverless', 'azure-functions', 'openwhisk', 
'aws-lambda', 'workflow', 'openfunction', 'dubbo-proxy', 'mqtt-proxy', 
'kafka-proxy', 'proxy-control', 'client-control', 'CSRF'].includes(plugin.name)

Review Comment:
   The hardcoded plugin list contains both 'csrf' and 'CSRF' entries. This 
duplication is redundant and could indicate inconsistency in plugin naming. If 
these represent the same plugin, one should be removed. If they are different 
plugins, the naming should be clarified to avoid confusion.
   ```suggestion
                 {['batch-requests', 'grpc-transcode', 'error-log-logger', 
'proxy-cache', 'http-logger', 'proxy-mirror', 'proxy-rewrite', 
'response-rewrite', 'request-id', 'tcp-logger', 'zipkin', 'udp-logger', 
'sls-logger', 'syslog', 'limit-conn', 'api-breaker', 'consumer-restriction', 
'basic-auth', 'fault-injection', 'ip-restriction', 'hmac-auth', 'key-auth', 
'limit-count', 'cors', 'limit-req', 'traffic-split', 'request-validation', 
'referer-restriction', 'wolf-rbac', 'jwt-auth', 'authz-casbin', 
'authz-keycloak', 'kafka-logger', 'openid-connect', 'prometheus', 'skywalking', 
'datadog', 'google-cloud-logging', 'uri-blocker', 'redirect', 'echo', 'gzip', 
'real-ip', 'server-info', 'grpc-web', 'mocking', 'authz-casdoor', 'cas-auth', 
'ldap-auth', 'opa', 'forward-auth', 'ext-plugin-pre-req', 
'ext-plugin-post-req', 'ext-plugin-post-resp', 'ua-restriction', 'csrf', 
'public-api', 'node-status', 'opentelemetry', 'skywalking-loggerr', 
'rocketmq-logger', 'clickhouse-logger', 'log-rotate', 'splunk
 -hec-logging', 'file-logger', 'loggly', 'elasticsearch-logger', 
'tencent-cloud-cls', 'serverless', 'azure-functions', 'openwhisk', 
'aws-lambda', 'workflow', 'openfunction', 'dubbo-proxy', 'mqtt-proxy', 
'kafka-proxy', 'proxy-control', 'client-control'].includes(plugin.name)
   ```



##########
website/src/css/landing-sections/architecture.scss:
##########
@@ -36,9 +36,10 @@
   font-family: MaisonNeue-Light, sans-serif;
   font-weight: 700;
   text-align: center;
-  position: relative;
-  bottom: -15px;
   font-size: 1rem;
+  line-height: 1.6;
+  margin: 20px 0;
+  padding: 10px;

Review Comment:
   The positioning properties `position: relative; bottom: -15px;` were removed 
from `.arch-card-caption > p` and replaced with `line-height: 1.6; margin: 20px 
0; padding: 10px;`. While this may improve the layout, the removal of relative 
positioning might affect the visual alignment that was previously intended. 
Verify that the caption text still aligns correctly with the architecture 
diagram after these changes.
   ```suggestion
     padding: 10px;
     position: relative;
     bottom: -15px;
   ```



##########
website/src/css/landing-sections/hero.scss:
##########
@@ -23,98 +52,223 @@
 
 .hero-subtitle {
   z-index: 100;
-  font-size: 1.1rem;
+  font-size: clamp(0.6rem, 2vw, 1.3rem);
   font-family: MaisonNeue-Light, sans-serif;
   position: relative;
-  color: #615d5d;
-  line-height: 30px;
-  letter-spacing: 0.2px;
+  color: #f1f5f9;
+  line-height: 1.6;
+  letter-spacing: 0.3px;
   margin: 25px 0;
-  padding-right: 20px;
+  padding-right: 0;
   animation-delay: 0.25s;
+  width: 100%;
+  max-width: 100%;
+  word-wrap: break-word;
+  overflow-wrap: break-word;
+  hyphens: auto;
+  box-sizing: border-box;
+  text-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6), 0 0 15px rgba(0, 0, 0, 0.4);
+  font-weight: 500;
+}
+
+.hero-subtitle[style*="color: #E8433E"] {
+  color: #ff4757 !important;
+  background: none !important;
+  -webkit-background-clip: unset !important;
+  -webkit-text-fill-color: unset !important;
+  background-clip: unset !important;
+  font-weight: 800;
+  font-size: clamp(0.8rem, 3vw, 2.2rem);
+  text-shadow: 2px 2px 6px rgba(0, 0, 0, 0.7), 0 0 20px rgba(0, 0, 0, 0.5);
+  margin: 20px 0 30px 0;
 }
 
 .hero-ctas {
   display: flex;
   align-items: center;
   animation-delay: 0.5;
+  gap: 20px;
+  margin-top: 32px;
 }
 
 .hero-sec-wrap {
-  display: flex;
-  background: #f4f4f4ad;
-  height: 100vh;
+  display: block !important;
+  background: transparent !important;
+  height: 100vh !important;
+  position: relative !important;
+  width: 100% !important;
+  margin-top: -60px !important;
+  padding-top: 60px !important;
 }
 
+
 .homeCanvas-overlay {
   position: absolute;
-  width: 50vw;
-  height: 100vh;
-  background: #fff;
-  top: -1px;
-  right: 0;
+  width: 100%;
+  height: 100%;
+  background: transparent;
+  top: 0;
+  left: 0;
+  z-index: 1;
+  pointer-events: none;
 }
 
 .homeCanvas {
-  width: 50vw;
-  height: 100vh;
+  width: 100% !important;
+  height: 100% !important;
+  position: absolute !important;
+  top: 0 !important;
+  left: 0 !important;
+  z-index: 1 !important;
+  opacity: 1 !important;
+  animation: float 6s ease-in-out infinite;
+  filter: contrast(1.1) brightness(1.05) saturate(1.1);
+}
+
+.hero-infograph {
+  position: absolute !important;
+  top: -60px !important;
+  left: 0 !important;
+  width: 100% !important;
+  height: calc(100% + 60px) !important;
+  z-index: 1 !important;
+  pointer-events: none !important;
 }
 
+
 .hero-text {
   height: 100%;
   display: flex;
   flex-wrap: wrap;
   align-content: center;
-  width: 50%;
-  padding: 0 0 0 6vw;
+  justify-content: center;
+  width: 80%;
+  max-width: 1200px;
+  padding: 60px 40px;
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  box-sizing: border-box;
+  z-index: 3;
+  text-align: center;
 }
 
 .hero-title {
   font-family: MaisonNeue-Bold, sans-serif;
-  color: #121212;
-  width: 42vw;
-  font-size: 4.2rem;
+  color: #ffffff !important;
+  width: 100% !important;
+  max-width: 100% !important;
+  font-size: clamp(1rem, 4vw, 4.5rem) !important;
   letter-spacing: 0.2px;
-  margin: 0;
+  margin: 0 0 30px 0;
+  position: relative;
+  line-height: 1.2;
+  word-wrap: break-word !important;
+  overflow-wrap: break-word !important;
+  hyphens: auto !important;
+  text-align: center;
+  text-shadow: 4px 4px 12px rgba(0, 0, 0, 1), 0 0 30px rgba(0, 0, 0, 0.9), 2px 
2px 6px rgba(0, 0, 0, 1);
+  font-weight: 900;

Review Comment:
   The hero section changes the text colors to white/light colors on what may 
be a variable background (animated canvas). The changes include:
   - `.hero-title` set to `color: #ffffff !important` (line 159)
   - `.hero-subtitle` set to `color: #f1f5f9` (line 58)
   - Text shadows added for contrast
   
   While text shadows are added, there's no guarantee of sufficient color 
contrast ratio (WCAG 4.5:1 for normal text, 3:1 for large text) if the canvas 
background becomes too light. The original design used dark text (`color: 
#121212`, `color: #615d5d`) on a light background which is more predictable for 
accessibility. Consider ensuring the canvas background maintains sufficient 
darkness or adding a semi-transparent overlay to guarantee contrast.



##########
website/src/pages/plugins.tsx:
##########
@@ -204,15 +204,19 @@ const Plugins: FC = () => {
       return (
         <div key={plugin.name}>
           <PluginCard href={plugin.beta ? 
`/docs/apisix/next/plugins/${pluginUrl}` : `/docs/apisix/plugins/${pluginUrl}`} 
target="_blank">
+
             <PluginIcon>
-              {plugin.useDefaultIcon
-                ? <img className="plugin-logo shadow default" 
src="/img/plugin/default-icon.png" alt={plugin.name} />
-                : (
+              {['batch-requests', 'grpc-transcode', 'error-log-logger', 
'proxy-cache', 'http-logger', 'proxy-mirror', 'proxy-rewrite', 
'response-rewrite', 'request-id', 'tcp-logger', 'zipkin', 'udp-logger', 
'sls-logger', 'syslog', 'limit-conn', 'api-breaker', 'consumer-restriction', 
'basic-auth', 'fault-injection', 'ip-restriction', 'hmac-auth', 'key-auth', 
'limit-count', 'cors', 'limit-req', 'traffic-split', 'request-validation', 
'referer-restriction', 'wolf-rbac', 'jwt-auth', 'authz-casbin', 
'authz-keycloak', 'kafka-logger', 'openid-connect', 'prometheus', 'skywalking', 
'datadog', 'google-cloud-logging', 'uri-blocker', 'redirect', 'echo', 'gzip', 
'real-ip', 'server-info', 'grpc-web', 'mocking', 'authz-casdoor', 'cas-auth', 
'ldap-auth', 'opa', 'forward-auth', 'ext-plugin-pre-req', 
'ext-plugin-post-req', 'ext-plugin-post-resp', 'ua-restriction', 'csrf', 
'public-api', 'node-status', 'opentelemetry', 'skywalking-loggerr', 
'rocketmq-logger', 'clickhouse-logger', 'log-rotate', 'splunk-h
 ec-logging', 'file-logger', 'loggly', 'elasticsearch-logger', 
'tencent-cloud-cls', 'serverless', 'azure-functions', 'openwhisk', 
'aws-lambda', 'workflow', 'openfunction', 'dubbo-proxy', 'mqtt-proxy', 
'kafka-proxy', 'proxy-control', 'client-control', 'CSRF'].includes(plugin.name)
+
+                ? (
                   <svg className="plugin-logo shadow" aria-hidden="true">
                     <use xlinkHref={`#icon${plugin.name}`} />
                   </svg>
+                ) : (
+                  <img className="plugin-logo shadow default" 
src="/img/plugin/default-icon.png" alt={plugin.name} />
                 )}

Review Comment:
   The plugin icon rendering logic appears to be inverted from the original 
implementation. Previously, plugins with `useDefaultIcon` property showed the 
default icon, while others showed SVG icons. Now the code checks if the plugin 
name is in a hardcoded list to show SVG icons, otherwise shows the default 
icon. 
   
   This inverts the logic because plugins NOT in the list will now show the 
default icon (img tag), whereas before plugins with `useDefaultIcon: false` 
would show SVG icons. This could cause incorrect icon rendering for plugins not 
in the hardcoded list.
   
   The original code checked: `plugin.useDefaultIcon ? showDefault : showSVG`
   The new code checks: `pluginNameInList ? showSVG : showDefault`
   
   This change breaks the abstraction provided by the `useDefaultIcon` property 
in plugin metadata and replaces it with a hardcoded list that needs manual 
maintenance.
   ```suggestion
                 {plugin.useDefaultIcon ? (
                   <img
                     className="plugin-logo shadow default"
                     src="/img/plugin/default-icon.png"
                     alt={plugin.name}
                   />
                 ) : (
                   <svg className="plugin-logo shadow" aria-hidden="true">
                     <use xlinkHref={`#icon${plugin.name}`} />
                   </svg>
                 )}
   ```



##########
website/src/css/customTheme.scss:
##########
@@ -150,15 +150,236 @@ header h2 {
   }
 }
 
-/* navbar */
-.navbar__link:hover,
-.navbar__link--active {
-  color: var(--color-primary);
+/* navbar - Default styling for all pages */
+.navbar {
+  background: #ffffff !important;
+  backdrop-filter: blur(10px) !important;
+  border-bottom: 1px solid rgba(0, 0, 0, 0.15) !important;
+  box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1) !important;
+  transition: all 0.3s ease !important;
 }
 
 .navbar__title {
   font-size: 18px;
   height: 30px;
+  color: #000000 !important;
+  font-weight: 800 !important;
+}
+
+.navbar__link {
+  color: #1a202c !important;
+  font-weight: 600 !important;
+  transition: all 0.3s ease !important;
+  padding: 8px 14px !important;
+  border-radius: 8px !important;
+  margin: 0 2px !important;
+}
+
+.navbar__link:hover,
+.navbar__link--active {
+  color: #000000 !important;
+  background: rgba(0, 0, 0, 0.08) !important;
+  font-weight: 700 !important;
+}
+
+.navbar__toggle {
+  color: #1a202c !important;
+  font-weight: 700 !important;
+  background: none !important;
+  border: none !important;
+  cursor: pointer !important;
+  z-index: 9999 !important;
+}
+
+.navbar__toggle:hover,
+.navbar__toggle:focus {
+  background: rgba(0, 0, 0, 0.1) !important;
+  border-radius: 4px !important;
+}
+
+.navbar__search-input {
+  background: rgba(0, 0, 0, 0.08) !important;
+  border: 1px solid rgba(0, 0, 0, 0.2) !important;
+  color: #000000 !important;
+  border-radius: 8px !important;
+  font-weight: 500 !important;
+}
+
+.navbar__search-input::placeholder {
+  color: rgba(0, 0, 0, 0.6) !important;
+  font-weight: 500 !important;
+}
+
+/* Mobile menu styling */
+.navbar-sidebar {
+  background: #ffffff !important;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1) !important;
+  z-index: 9999 !important;
+  position: fixed !important;
+  top: 0 !important;
+  right: 0 !important;
+  height: 100vh !important;
+  width: 300px !important;
+  transform: translateX(0) !important;
+}
+
+.navbar-sidebar__brand {
+  background: #ffffff !important;
+  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1) !important;
+  padding: 16px !important;
+}
+
+.navbar-sidebar__items {
+  background: #ffffff !important;
+  padding: 20px 0 !important;
+  overflow-y: auto !important;
+}
+
+.navbar-sidebar .menu__link {
+  color: #1a202c !important;
+  font-weight: 600 !important;
+  padding: 12px 16px !important;
+  border-radius: 8px !important;
+  margin: 4px 8px !important;
+  display: block !important;
+  text-decoration: none !important;
+}
+
+.navbar-sidebar .menu__link:hover,
+.navbar-sidebar .menu__link--active {
+  background: rgba(0, 0, 0, 0.08) !important;
+  color: #000000 !important;
+}
+
+.navbar-sidebar__backdrop {
+  background: rgba(0, 0, 0, 0.5) !important;
+  z-index: 9998 !important;
+}
+
+/* Hero section mobile menu */
+.hero-navbar .navbar-sidebar {
+  background: rgba(0, 0, 0, 0.95) !important;
+  z-index: 9999 !important;
+  position: fixed !important;
+  top: 0 !important;
+  right: 0 !important;
+  height: 100vh !important;
+  width: 300px !important;
+}
+
+.hero-navbar .navbar-sidebar__brand {
+  background: rgba(0, 0, 0, 0.95) !important;
+  padding: 16px !important;
+}
+
+.hero-navbar .navbar-sidebar__items {
+  background: rgba(0, 0, 0, 0.95) !important;
+  padding: 20px 0 !important;
+}
+
+.hero-navbar .navbar-sidebar .menu__link {
+  color: #ffffff !important;
+  text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5) !important;
+  font-weight: 600 !important;
+  padding: 12px 16px !important;
+  border-radius: 8px !important;
+  margin: 4px 8px !important;
+  display: block !important;
+  text-decoration: none !important;
+}
+
+.hero-navbar .navbar-sidebar .menu__link:hover,
+.hero-navbar .navbar-sidebar .menu__link--active {
+  background: rgba(255, 255, 255, 0.2) !important;
+  color: #ffffff !important;
+}
+
+.hero-navbar .navbar-sidebar__backdrop {
+  background: rgba(0, 0, 0, 0.7) !important;
+  z-index: 9998 !important;
+}
+
+/* Hero section specific navbar styling - only when in hero viewport */
+.hero-navbar .navbar {
+  background: rgba(0, 0, 0, 0.7) !important;
+  border-bottom: 1px solid rgba(255, 255, 255, 0.3) !important;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3) !important;
+}
+
+/* Mobile specific navbar enhancement */
+@media (max-width: 768px) {
+  .hero-navbar .navbar {
+    background: rgba(0, 0, 0, 0.85) !important;
+    border-bottom: 2px solid rgba(255, 255, 255, 0.4) !important;
+    box-shadow: 0 6px 25px rgba(0, 0, 0, 0.4) !important;
+  }
+  
+  .hero-navbar .navbar__title {
+    font-size: 1.1rem !important;
+    font-weight: 900 !important;
+    text-shadow: 2px 2px 6px rgba(0, 0, 0, 1) !important;
+  }
+  
+  .hero-navbar .navbar__link {
+    font-size: 0.9rem !important;
+    font-weight: 700 !important;
+    text-shadow: 2px 2px 6px rgba(0, 0, 0, 1) !important;
+    padding: 10px 14px !important;
+  }
+  
+  .hero-navbar .navbar__toggle {
+    font-size: 1.2rem !important;
+    font-weight: 900 !important;
+    text-shadow: 2px 2px 6px rgba(0, 0, 0, 1) !important;
+  }
+}
+
+.hero-navbar .navbar__title {
+  color: #ffffff !important;
+  text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3) !important;
+}
+
+.hero-navbar .navbar__link {
+  color: rgba(255, 255, 255, 0.9) !important;
+  text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3) !important;
+  padding: 8px 16px !important;
+  border-radius: 20px !important;
+  margin: 0 4px !important;
+}
+
+.hero-navbar .navbar__link:hover,
+.hero-navbar .navbar__link--active {
+  color: #ffffff !important;
+  background: rgba(255, 255, 255, 0.2) !important;
+  backdrop-filter: blur(10px) !important;
+  text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.5) !important;
+  transform: translateY(-1px) !important;
+}
+
+.hero-navbar .navbar__toggle {
+  color: #ffffff !important;
+  background: none !important;
+  border: none !important;
+  cursor: pointer !important;
+  z-index: 9999 !important;
+}
+
+.hero-navbar .navbar__toggle:hover,
+.hero-navbar .navbar__toggle:focus {
+  background: rgba(255, 255, 255, 0.2) !important;
+  border-radius: 4px !important;
+}
+
+.hero-navbar .navbar__search-input {
+  background: rgba(255, 255, 255, 0.2) !important;
+  border: 1px solid rgba(255, 255, 255, 0.3) !important;
+  color: #ffffff !important;
+  backdrop-filter: blur(10px) !important;
+  border-radius: 20px !important;
+}
+
+.hero-navbar .navbar__search-input::placeholder {
+  color: rgba(255, 255, 255, 0.7) !important;

Review Comment:
   The extensive use of `!important` flags throughout the navbar styles (lines 
155-383) is an anti-pattern that can make future style overrides difficult and 
indicates potential CSS specificity issues. There are over 50 instances of 
`!important` in this section alone.
   
   While `!important` might be needed to override Docusaurus default styles, 
this many instances suggest the styles should be placed in a location with 
higher specificity rather than forcing precedence. This makes the stylesheet 
fragile and harder to maintain or debug when style conflicts occur.
   ```suggestion
   :root .hero-navbar .navbar__toggle {
     color: #ffffff;
     background: none;
     border: none;
     cursor: pointer;
     z-index: 9999;
   }
   
   :root .hero-navbar .navbar__toggle:hover,
   :root .hero-navbar .navbar__toggle:focus {
     background: rgba(255, 255, 255, 0.2);
     border-radius: 4px;
   }
   
   :root .hero-navbar .navbar__search-input {
     background: rgba(255, 255, 255, 0.2);
     border: 1px solid rgba(255, 255, 255, 0.3);
     color: #ffffff;
     backdrop-filter: blur(10px);
     border-radius: 20px;
   }
   
   :root .hero-navbar .navbar__search-input::placeholder {
     color: rgba(255, 255, 255, 0.7);
   ```



##########
website/src/pages/plugins.tsx:
##########
@@ -204,15 +204,19 @@ const Plugins: FC = () => {
       return (
         <div key={plugin.name}>
           <PluginCard href={plugin.beta ? 
`/docs/apisix/next/plugins/${pluginUrl}` : `/docs/apisix/plugins/${pluginUrl}`} 
target="_blank">
+
             <PluginIcon>
-              {plugin.useDefaultIcon
-                ? <img className="plugin-logo shadow default" 
src="/img/plugin/default-icon.png" alt={plugin.name} />
-                : (
+              {['batch-requests', 'grpc-transcode', 'error-log-logger', 
'proxy-cache', 'http-logger', 'proxy-mirror', 'proxy-rewrite', 
'response-rewrite', 'request-id', 'tcp-logger', 'zipkin', 'udp-logger', 
'sls-logger', 'syslog', 'limit-conn', 'api-breaker', 'consumer-restriction', 
'basic-auth', 'fault-injection', 'ip-restriction', 'hmac-auth', 'key-auth', 
'limit-count', 'cors', 'limit-req', 'traffic-split', 'request-validation', 
'referer-restriction', 'wolf-rbac', 'jwt-auth', 'authz-casbin', 
'authz-keycloak', 'kafka-logger', 'openid-connect', 'prometheus', 'skywalking', 
'datadog', 'google-cloud-logging', 'uri-blocker', 'redirect', 'echo', 'gzip', 
'real-ip', 'server-info', 'grpc-web', 'mocking', 'authz-casdoor', 'cas-auth', 
'ldap-auth', 'opa', 'forward-auth', 'ext-plugin-pre-req', 
'ext-plugin-post-req', 'ext-plugin-post-resp', 'ua-restriction', 'csrf', 
'public-api', 'node-status', 'opentelemetry', 'skywalking-loggerr', 
'rocketmq-logger', 'clickhouse-logger', 'log-rotate', 'splunk-h
 ec-logging', 'file-logger', 'loggly', 'elasticsearch-logger', 
'tencent-cloud-cls', 'serverless', 'azure-functions', 'openwhisk', 
'aws-lambda', 'workflow', 'openfunction', 'dubbo-proxy', 'mqtt-proxy', 
'kafka-proxy', 'proxy-control', 'client-control', 'CSRF'].includes(plugin.name)

Review Comment:
   The hardcoded plugin list contains 'skywalking-loggerr' with a double 'r', 
which appears to be a typo. This should likely be 'skywalking-logger' with a 
single 'r' to match the correct plugin name.
   ```suggestion
                 {['batch-requests', 'grpc-transcode', 'error-log-logger', 
'proxy-cache', 'http-logger', 'proxy-mirror', 'proxy-rewrite', 
'response-rewrite', 'request-id', 'tcp-logger', 'zipkin', 'udp-logger', 
'sls-logger', 'syslog', 'limit-conn', 'api-breaker', 'consumer-restriction', 
'basic-auth', 'fault-injection', 'ip-restriction', 'hmac-auth', 'key-auth', 
'limit-count', 'cors', 'limit-req', 'traffic-split', 'request-validation', 
'referer-restriction', 'wolf-rbac', 'jwt-auth', 'authz-casbin', 
'authz-keycloak', 'kafka-logger', 'openid-connect', 'prometheus', 'skywalking', 
'datadog', 'google-cloud-logging', 'uri-blocker', 'redirect', 'echo', 'gzip', 
'real-ip', 'server-info', 'grpc-web', 'mocking', 'authz-casdoor', 'cas-auth', 
'ldap-auth', 'opa', 'forward-auth', 'ext-plugin-pre-req', 
'ext-plugin-post-req', 'ext-plugin-post-resp', 'ua-restriction', 'csrf', 
'public-api', 'node-status', 'opentelemetry', 'skywalking-logger', 
'rocketmq-logger', 'clickhouse-logger', 'log-rotate', 'splunk-
 hec-logging', 'file-logger', 'loggly', 'elasticsearch-logger', 
'tencent-cloud-cls', 'serverless', 'azure-functions', 'openwhisk', 
'aws-lambda', 'workflow', 'openfunction', 'dubbo-proxy', 'mqtt-proxy', 
'kafka-proxy', 'proxy-control', 'client-control', 'CSRF'].includes(plugin.name)
   ```



##########
website/src/components/sections/HeroSection.tsx:
##########
@@ -24,39 +21,69 @@ const LazyLoadHeroCanvas = () => {
   );
 };
 
-const HeroSection: FC = () => (
-  <div className="hero-sec-wrap" style={{ width: '100%' }}>
-    <div className="hero-text">
-      <h1 className="hero-title">
-        <Translate id="hero.component.title.fragment1">API Gateway & AI 
Gateway for APIs and AI Agents</Translate>
-      </h1>
-      <h2
-        className="hero-subtitle"
-        style={{
-          color: '#E8433E', fontSize: 32, fontWeight: 700, lineHeight: 1.2,
-        }}
-      >
-        <Translate id="hero.component.title.fragment2">
-          Open-Source, Community-Driven, Future-Ready
-        </Translate>
-      </h2>
-      <h3 className="hero-subtitle">
-        <Translate id="hero.component.subtitle.content">
-          APISIX API Gateway provides rich traffic management features like 
load balancing, dynamic
-          upstream, canary release, circuit breaking, auth, and observability.
-        </Translate>
-      </h3>
-      <div className="hero-ctas">
-        <Link target="_parent" to={useBaseUrl('docs/apisix/getting-started')} 
className="btn btn-download">
-          <Translate id="hero.component.download.btn">Getting 
Started</Translate>
-        </Link>
-        <ArrowAnim />
-      </div>
-    </div>
-    <div className="add-margin">
+const HeroSection: FC = () => {
+  useEffect(() => {
+    const handleScroll = () => {
+      const heroSection = document.querySelector('.hero-sec-wrap');
+      const navbar = document.querySelector('.navbar');
+      
+      if (heroSection && navbar) {
+        const heroRect = heroSection.getBoundingClientRect();
+        const isInHeroSection = heroRect.top <= 100 && heroRect.bottom >= 0;
+        
+        if (isInHeroSection) {
+          document.body.classList.add('hero-navbar');
+        } else {
+          document.body.classList.remove('hero-navbar');
+        }
+      }
+    };
+
+    // Set initial state
+    handleScroll();
+    
+    // Add scroll listener
+    window.addEventListener('scroll', handleScroll);

Review Comment:
   The scroll event listener in the useEffect hook fires on every scroll event 
without throttling or debouncing. This can cause performance issues as the 
handler performs DOM queries on every scroll event. Consider using a throttle 
or debounce mechanism to limit how frequently the scroll handler executes, 
especially since the logic only needs to toggle a class based on the hero 
section's visibility.



##########
website/src/components/sections/HeroSection.tsx:
##########
@@ -1,5 +1,5 @@
 import type { FC } from 'react';
-import React from 'react';
+import React, { useEffect } from 'react';

Review Comment:
   The import statement for `useWindowType` is present but the hook is no 
longer used in the component after removing the mobile check logic. This unused 
import should be removed to keep the code clean.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to