Skip to content

feat(frontend): redesign landing page with light-themed right panels#1807

Open
jaseemjaskp wants to merge 34 commits intomainfrom
feature/landing-page-redesign-oss
Open

feat(frontend): redesign landing page with light-themed right panels#1807
jaseemjaskp wants to merge 34 commits intomainfrom
feature/landing-page-redesign-oss

Conversation

@jaseemjaskp
Copy link
Contributor

@jaseemjaskp jaseemjaskp commented Feb 25, 2026

What

Redesign the landing page with new light-themed right panels for all three variants (default, LLM Whisperer, Unstract), featuring compliance badges, stats cards, testimonials, and provider logos.

Why

Updated to match new Figma design specifications with a modern, trust-building layout that showcases compliance certifications, usage stats, customer testimonials, and integration partners.

How

  • Redesign all three landing page variants (default, LLM Whisperer, Unstract) with light-themed right panels
  • Add compliance badges (SOC2, GDPR, ISO, HIPAA, G2)
  • Add stats cards with gradient icons
  • Add testimonials with gradient borders
  • Add provider/trusted-by logos
  • Add product toggle switcher and region selector with flag icons
  • Update left panel vertical spacing to match Figma design (48px between sections)
  • Fix Ant Design font-weight override on card titles

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • No. This PR only changes the landing page layout and styling. No backend changes, no routing changes, and no changes to authenticated pages. Existing functionality remains unaffected.

Database Migrations

  • None

Env Config

  • None

Relevant Docs

  • N/A

Related Issues or PRs

  • N/A

Dependencies Versions

  • No new dependencies added

Notes on Testing

  • Navigate to /landing — verify default landing page with two product cards (Unstract, LLMWhisperer)
  • Navigate to /landing?selectedProduct=llm-whisperer — verify LLM Whisperer variant with stats, testimonial, and LLM providers
  • Navigate to /landing?selectedProduct=unstract — verify Unstract variant with stats, testimonial, and trusted-by logos
  • Verify product toggle switches between Unstract and LLMWhisperer variants
  • Verify region selector (USA/Europe) updates selection state
  • Check responsive behavior at different viewport widths

Screenshots

Screenshot 2026-02-25 at 14 37 10

Checklist

I have read and understood the Contribution Guidelines.

hari-kuriakose and others added 29 commits October 20, 2025 15:43
Migrate the Unstract frontend build system from Create React App (react-scripts 5.0.1) to Vite 6.0.5 for improved development experience and build performance.

Key Changes:
- Replace react-scripts with Vite 6.0.5 and @vitejs/plugin-react 4.3.4
- Move index.html from public/ to root directory
- Replace setupProxy.js with Vite proxy configuration
- Update environment variables from REACT_APP_* to VITE_* prefix
- Configure esbuild to handle JSX in .js files
- Add comprehensive migration documentation

Build Optimizations:
- Manual chunk splitting for react, antd, and pdf vendors
- Dependency pre-bundling for faster cold starts
- HMR with polling enabled for Docker volume compatibility

Documentation:
- Add VITE_MIGRATION.md with comprehensive migration guide
- Update README.md with Vite-specific configuration and commands
- Document environment variable migration and troubleshooting

Performance Benefits:
- Development server startup: 10-30s → 1-2s
- Hot Module Replacement: 2-5s → <1s
- Production build time: 60-120s → 30-60s

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ports

The codebase extensively uses SVG imports with ?react query syntax
(39 imports in src/assets/index.js). vite-plugin-svgr is required to
transform these imports into React components.

Changes:
- Add vite-plugin-svgr@^4.5.0 to devDependencies
- Restore svgr plugin in vite.config.js
- Add vite-plugin-svgr type references in vite-env.d.ts
- Remove conflicting public/index.html from CRA migration

Fixes white screen issue caused by SVG components failing to render.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ntation

The README documentation showed incorrect HMR clientPort configuration
using process.env instead of the env variable from loadEnv.

Changes:
- Update clientPort example to use env.WDS_SOCKET_PORT (not process.env)
- Change from falsy coalescing to explicit conditional check
- Ensure documentation matches vite.config.js implementation

Addresses CodeRabbit feedback on PR #1607.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…mentation

The README proxy configuration example incorrectly used process.env
instead of the env variable from loadEnv.

Changes:
- Update proxy target to use env.VITE_BACKEND_URL (not process.env)
- Ensure documentation matches vite.config.js implementation
- Maintain consistency across all Vite configuration examples

Addresses CodeRabbit critical feedback on PR #1607.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
# Conflicts:
#	docker/dockerfiles/frontend.Dockerfile
#	frontend/package-lock.json
…e compatibility

Converted all require() calls in frontend/src to use try/catch with
top-level await import() to support Vite's native ES module system.
Plugin imports remain optional via try/catch to preserve OSS compatibility
where plugin files are not present.

Special cases:
- Pipelines.jsx: static import (non-plugin, always available)
- DsSettingsCard.jsx: async IIFE inside useEffect
- Make selectedPrompts optional in CombinedOutput since ToolsMain
  does not pass it and the component handles undefined
- Change llmProfiles PropType from string to array in JsonViewBody
  to match the actual data type
- Change coverageCountData from PropTypes.object to PropTypes.array in
  PromptCardWrapper, PromptCard, and PromptCardItems
- Fix PropTypes.text (undefined) to PropTypes.string for promptKey and
  promptText in PromptCardItems
- Change highlightData to PropTypes.oneOfType([object, array]) in
  DisplayPromptResult
- Change apiService from PropTypes.func to PropTypes.object in ManageKeys
- Change connMode from required to optional in ConfigureConnectorModal
- Change type from required to optional in ListOfSources
Add optionalPluginImports() Rollup plugin to vite.config.js that
resolves missing plugin paths to an empty module at build time instead
of failing. This allows the existing try/catch dynamic import pattern
to work during production builds when plugin files are absent.
The codebase uses top-level await for optional plugin imports, which
requires es2022+. Vite's default target (es2020) does not support
this, causing the build to fail.
- Switch Dockerfile base image from node:20-alpine to oven/bun:1-alpine
- Replace npm install/run commands with bun equivalents in Dockerfile
- Remove engines.npm constraint, update engines.node to >=18.0.0
- Replace npm run with bun run in lint:all script
- Delete package-lock.json, add bun.lock
…1771)

* feat: replace ESLint and Prettier with Biome for frontend linting and formatting

- Add @biomejs/biome v2.3.13 as dev dependency
- Create biome.json with migrated ESLint rules and formatter config
- Update package.json scripts (lint, format, check) to use Biome
- Remove ESLint and Prettier dependencies and .eslintrc.json
- Add Biome pre-commit hook to .pre-commit-config.yaml
- Fix undeclared sessionDetails variable in HeaderTitle.jsx
- Fix Error() and Array() to use new keyword
- Fix prismjs import order in CombinedOutput.jsx
- Reformat all frontend source files with Biome

* fix: skip biome-check in pre-commit CI and add robust flags

- Add biome-check to ci.skip list since pre-commit.ci lacks
  reliable npm registry access for language:system hooks
- Add --files-ignore-unknown=true and --no-errors-on-unmatched
  flags to the biome-check hook entry for robustness
- Update Node.js requirement to >= 18.0.0
- Replace ESLint/Prettier with Biome in editor setup
- Update linting/formatting commands for Biome
- Add biome.json to project structure
- Add Biome documentation links to learning resources
- Upgrade vite from ^6.0.5 to ^7.0.0 (installed 7.3.1)
- Upgrade vitest from ^2.1.8 to ^3.2.0 (installed 3.2.4)
- Upgrade @vitejs/plugin-react from ^4.3.4 to ^4.4.0
- Update Node.js engine requirement from >=18.0.0 to >=20.19.0
- Modernize __dirname to import.meta.dirname in vite.config.js
- Update Vite badge from 6.x to 7.x
- Update Node.js requirement from 18.0.0 to 20.19.0
- Update prerequisites to list Bun as primary package manager
- Replace all npm commands with bun equivalents
- Update install, dev, build, test, and lint commands
- Add Vite 7 upgrade section with version updates and changes
- Update all npm commands to use bun
- Update package versions to current (Vite 7.3.1, Vitest 3.2.4)
- Document Node.js 20.19+ requirement
…mode

When visiting /verticals/* in incognito, selectedProduct from localStorage
is null, causing isUnstract to be true and showing the Unstract logo and
setup incomplete banner instead of the API Hub layout.

Add URL-based fallback to detect verticals route and set the effective
product accordingly.

UN-3219
Redesign all three landing page variants (default, LLM Whisperer, Unstract)
with new light-themed right panels featuring compliance badges, stats cards,
testimonials with gradient borders, and provider logos. Update left panel
spacing to match Figma design specifications.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 25, 2026

Summary by CodeRabbit

Release Notes

  • New Features

    • Added multiple themed variants for the login page right panel with distinctive visual styles.
    • Introduced new content sections and UI components for enhanced layout presentation.
    • Added region selector and product toggle controls.
  • Style

    • Enhanced login page typography, spacing, and layout alignment.
    • Improved badge, logo, and stat card styling across themed variants.
    • Refined visual hierarchy with decorative elements and overlays.

Walkthrough

Login styling system expanded with themed variants, ProductContentLayout component refactored to hardcoded content with new exports, and vite configuration formatting normalized for consistency.

Changes

Cohort / File(s) Summary
Login Styling
frontend/src/components/log-in/Login.css
Extensive CSS additions for themed right-panel variants (llm-whisperer, unstract, default-light) with decorative overlays, badges, logos, stat cards, testimonials, region selectors, and trust indicators. Logo sizing and typography spacing refined.
ProductContentLayout Component
frontend/src/components/log-in/ProductContentLayout.jsx
Rewrote component to eliminate external props and hardcode content. Removed PropTypes declarations. Added LlmWhispererContent and UnstractContent as new exports alongside ProductContentLayout. Introduced internal data structures for compliance badges, logos, providers, and stats.
Vite Configuration
frontend/vite.config.js
Normalized quote style from single to double quotes throughout, added trailing semicolons for consistency. Minor structural refinements to server proxy and build chunk naming. No functional behavior changes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: redesigning the landing page with light-themed right panels, which aligns with the core modifications across CSS, JSX, and configuration files.
Description check ✅ Passed The description comprehensively covers all required template sections with detailed information about what changed, why, how it was implemented, testing procedures, and explicit confirmation of no feature breakage.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/landing-page-redesign-oss

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Signed-off-by: Jaseem Jas <89440144+jaseemjaskp@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
frontend/src/components/log-in/Login.css (2)

282-289: Consider scoped selectors instead of !important for Ant Design overrides.

Multiple rules use !important to override Ant Design defaults. While this works, it can lead to specificity escalation over time. Wrapping with a more specific selector (e.g., .llm-whisperer-content .llm-headline) may achieve the same result without !important.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/log-in/Login.css` around lines 282 - 289, Replace the
use of "!important" on the .llm-headline rule by increasing selector specificity
instead: wrap or prefix the rule with a parent scope such as
.llm-whisperer-content .llm-headline (or another component root class) and
remove all "!important" tokens so the styles (font-size, font-weight,
line-height, text-align, color, margin-bottom) naturally override Ant Design
defaults via specificity rather than force. Ensure the selector you choose
exists in the component markup and apply the same scoping approach to any other
rules in this file using "!important".

998-1010: Consider consolidating duplicate CSS rules across theme variants.

These .llm-light-stat-card and .unstract-light-stat-card blocks are identical. Similar duplication exists for:

  • *-content containers
  • *-testimonial sections
  • *-badges-row rules
  • *-stat-icon, *-stat-value, *-stat-label rules

A shared base class (e.g., .light-stat-card) with theme-specific modifiers would reduce maintenance burden and file size.

♻️ Example consolidation approach
/* Shared base styles */
.light-stat-card {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 20px 12px 16px;
  border-radius: 10px;
  border: 1px solid `#e8edf2`;
  background: `#fff`;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  box-sizing: border-box;
}

/* Then use: class="light-stat-card llm-light-stat-card" for any variant overrides */

Also applies to: 1222-1234

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/log-in/Login.css` around lines 998 - 1010, The CSS
duplicates multiple theme variants (e.g., .llm-light-stat-card and
.unstract-light-stat-card, and similar pairs for *-content, *-testimonial,
*-badges-row, *-stat-icon, *-stat-value, *-stat-label) — create shared base
classes (e.g., .light-stat-card, .light-stat-content, .light-testimonial,
.light-badges-row, .light-stat-icon, .light-stat-value, .light-stat-label)
containing the common rules and move variant-specific overrides into modifier
classes (keep .llm-* and .unstract-* only for differences); update the markup to
apply both the base class and the variant modifier (e.g., class="light-stat-card
llm-light-stat-card") so styles are consolidated and duplicate blocks removed.
frontend/src/components/navigations/top-nav-bar/TopNavBar.jsx (1)

177-183: LGTM — URL-based fallback logic is correct.

The fallback mechanism properly handles incognito/unauthenticated users on verticals routes. The boolean derivations are logically sound.

Minor readability suggestion: the double-negation in isUnstract could be simplified:

♻️ Optional: simplify isUnstract expression
-const isUnstract = !(effectiveProduct && effectiveProduct !== "unstract");
+const isUnstract = !effectiveProduct || effectiveProduct === "unstract";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/navigations/top-nav-bar/TopNavBar.jsx` around lines
177 - 183, The current isUnstract uses a confusing double-negation; simplify it
by deriving isUnstract directly from effectiveProduct so it is true when
effectiveProduct is falsy or equals "unstract" (i.e., replace the
!(effectiveProduct && effectiveProduct !== "unstract") logic with an explicit
check that covers both cases) — update the const isUnstract declaration in
TopNavBar.jsx where effectiveProduct is computed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/components/log-in/Login.css`:
- Around line 21-27: The .login-right-section currently uses overflow: hidden
and height: 100vh causing content clipping on small viewports; update the CSS to
add a mobile media query (e.g., for max-width: 768px or Ant Design xs
breakpoint) that changes .login-right-section to height: auto (or remove fixed
100vh), set overflow-y: auto, and/or set width: 100% so the section stacks
vertically with the left column (or switch the parent layout to flex-direction:
column); ensure ProductContentLayout content can scroll/expand on small screens
to avoid clipping.

In `@frontend/src/components/log-in/ProductContentLayout.jsx`:
- Around line 42-47: There are duplicate constant arrays; remove the redundant
definitions (LLM_PROVIDERS, TRUSTED_BY_LOGOS, UNSTRACT_COMPLIANCE_BADGES) and
update all usages to reference the existing defaults (DEFAULT_LLM_PROVIDERS,
DEFAULT_TRUSTED_LOGOS, DEFAULT_COMPLIANCE_BADGES) so the component
(ProductContentLayout) and any other consumers import/use the single source of
truth—search for and replace references to LLM_PROVIDERS →
DEFAULT_LLM_PROVIDERS, TRUSTED_BY_LOGOS → DEFAULT_TRUSTED_LOGOS, and
UNSTRACT_COMPLIANCE_BADGES → DEFAULT_COMPLIANCE_BADGES, then delete the
now-unused duplicate constant declarations and remove any related unused
imports.
- Around line 2-25: ProductContentLayout.jsx currently imports 24 asset modules
(e.g., anthropicLogo, azureGptLogo, llmG2Badge, gregCrisciPhoto,
christopherVarnerPhoto, unstractQuoteIcon, etc.) from non-existent
../../plugins/assets/... paths which breaks the build; fix the imports in
ProductContentLayout.jsx by either (A) replacing each ../../plugins/assets/...
import with the correct existing paths under frontend/src/assets/ for the
matching files, or (B) removing/conditionally loading unused assets and
substituting available placeholders, ensuring all referenced symbols
(anthropicLogo, openAiLogo, statIconAccuracy, unstractStatIconEfficiency, etc.)
resolve to actual files or exports before committing.

---

Nitpick comments:
In `@frontend/src/components/log-in/Login.css`:
- Around line 282-289: Replace the use of "!important" on the .llm-headline rule
by increasing selector specificity instead: wrap or prefix the rule with a
parent scope such as .llm-whisperer-content .llm-headline (or another component
root class) and remove all "!important" tokens so the styles (font-size,
font-weight, line-height, text-align, color, margin-bottom) naturally override
Ant Design defaults via specificity rather than force. Ensure the selector you
choose exists in the component markup and apply the same scoping approach to any
other rules in this file using "!important".
- Around line 998-1010: The CSS duplicates multiple theme variants (e.g.,
.llm-light-stat-card and .unstract-light-stat-card, and similar pairs for
*-content, *-testimonial, *-badges-row, *-stat-icon, *-stat-value, *-stat-label)
— create shared base classes (e.g., .light-stat-card, .light-stat-content,
.light-testimonial, .light-badges-row, .light-stat-icon, .light-stat-value,
.light-stat-label) containing the common rules and move variant-specific
overrides into modifier classes (keep .llm-* and .unstract-* only for
differences); update the markup to apply both the base class and the variant
modifier (e.g., class="light-stat-card llm-light-stat-card") so styles are
consolidated and duplicate blocks removed.

In `@frontend/src/components/navigations/top-nav-bar/TopNavBar.jsx`:
- Around line 177-183: The current isUnstract uses a confusing double-negation;
simplify it by deriving isUnstract directly from effectiveProduct so it is true
when effectiveProduct is falsy or equals "unstract" (i.e., replace the
!(effectiveProduct && effectiveProduct !== "unstract") logic with an explicit
check that covers both cases) — update the const isUnstract declaration in
TopNavBar.jsx where effectiveProduct is computed.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 437266e and b9cf878.

📒 Files selected for processing (3)
  • frontend/src/components/log-in/Login.css
  • frontend/src/components/log-in/ProductContentLayout.jsx
  • frontend/src/components/navigations/top-nav-bar/TopNavBar.jsx

Comment on lines +21 to +27
overflow: hidden;
background-color: #eceff3;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's find and examine the Login.css file
find . -name "Login.css" -type f | head -5

Repository: Zipstack/unstract

Length of output: 103


🏁 Script executed:

# Check file size and read the relevant section
wc -l frontend/src/components/log-in/Login.css

Repository: Zipstack/unstract

Length of output: 106


🏁 Script executed:

# Read around lines 1-50 to see the .login-right-section and its full context
sed -n '1,50p' frontend/src/components/log-in/Login.css

Repository: Zipstack/unstract

Length of output: 961


🏁 Script executed:

# Look for all instances of login-right-section and its parent to understand the layout
rg -n 'login-right-section|login-container|overflow' frontend/src/components/log-in/Login.css | head -30

Repository: Zipstack/unstract

Length of output: 707


🏁 Script executed:

# Check for media queries in the file
rg -n '@media' frontend/src/components/log-in/Login.css

Repository: Zipstack/unstract

Length of output: 43


🏁 Script executed:

# Let's see the full structure - read sections around the login-right-section
sed -n '1,100p' frontend/src/components/log-in/Login.css | cat -n

Repository: Zipstack/unstract

Length of output: 2719


🏁 Script executed:

# Find the Login component file
find . -path "*/log-in/Login.*" -type f | grep -E "\.(tsx?|jsx?)$"

Repository: Zipstack/unstract

Length of output: 103


🏁 Script executed:

# Check the Login component structure
head -100 frontend/src/components/log-in/Login.tsx

Repository: Zipstack/unstract

Length of output: 160


🏁 Script executed:

# Look for login-right-section usage in the component
rg -n 'login-right-section' frontend/src/components/log-in/Login.tsx -B 5 -A 10 | head -40

Repository: Zipstack/unstract

Length of output: 141


🏁 Script executed:

# Check if there are any responsive styles or tailwind classes in the component
rg -n 'responsive|mobile|md:|sm:|lg:' frontend/src/components/log-in/Login.tsx | head -20

Repository: Zipstack/unstract

Length of output: 141


🏁 Script executed:

# Check the component file size and examine the right section rendering
wc -l frontend/src/components/log-in/Login.tsx
sed -n '1,200p' frontend/src/components/log-in/Login.tsx | tail -100

Repository: Zipstack/unstract

Length of output: 216


🏁 Script executed:

# Read the Login.jsx component
head -150 frontend/src/components/log-in/Login.jsx

Repository: Zipstack/unstract

Length of output: 1962


🏁 Script executed:

# Search for login-right-section in the JSX file
rg -n 'login-right-section' frontend/src/components/log-in/Login.jsx -B 5 -A 15

Repository: Zipstack/unstract

Length of output: 424


🏁 Script executed:

# Check the full file size and structure
wc -l frontend/src/components/log-in/Login.jsx

Repository: Zipstack/unstract

Length of output: 104


🏁 Script executed:

# Look for responsive design patterns in the component
rg -n 'window\.innerWidth|useWindowSize|@media|media.*query|responsive' frontend/src/components/log-in/Login.jsx

Repository: Zipstack/unstract

Length of output: 43


🏁 Script executed:

# Check what's rendered in the right section
sed -n '1,300p' frontend/src/components/log-in/Login.jsx | grep -A 20 'login-right-section'

Repository: Zipstack/unstract

Length of output: 259


🏁 Script executed:

# Find ProductContentLayout
find . -name "ProductContentLayout*" -type f

Repository: Zipstack/unstract

Length of output: 118


🏁 Script executed:

# Examine ProductContentLayout
head -80 frontend/src/components/log-in/ProductContentLayout.jsx

Repository: Zipstack/unstract

Length of output: 3919


🏁 Script executed:

# Check if there are CSS overrides for responsive behavior
rg -n 'xs=|sm=|md=|lg=' frontend/src/components/log-in/Login.jsx

Repository: Zipstack/unstract

Length of output: 197


🏁 Script executed:

# Look for any media queries or responsive styles targeting login sections
rg -n '@media' frontend/src/components/log-in/ProductContentLayout.css 2>/dev/null || echo "No CSS file found"

Repository: Zipstack/unstract

Length of output: 78


🏁 Script executed:

# Check what CSS files exist in log-in directory
ls -la frontend/src/components/log-in/

Repository: Zipstack/unstract

Length of output: 374


Add responsive styles to prevent content clipping on smaller viewports.

The .login-right-section uses overflow: hidden with a fixed height: 100vh, but has no media queries to adapt for smaller screens. On mobile (where Ant Design's xs={24} makes the section full-width), the tall ProductContentLayout content will be clipped and inaccessible.

Consider adding a media query to adjust the layout on smaller breakpoints:

  • Increase the height constraint or use overflow-y: auto on mobile
  • Or restructure the layout to stack sections vertically on small screens
Current CSS
.login-right-section {
  width: 50%;
  height: 100vh;
  overflow: hidden;
  /* ... */
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/log-in/Login.css` around lines 21 - 27, The
.login-right-section currently uses overflow: hidden and height: 100vh causing
content clipping on small viewports; update the CSS to add a mobile media query
(e.g., for max-width: 768px or Ant Design xs breakpoint) that changes
.login-right-section to height: auto (or remove fixed 100vh), set overflow-y:
auto, and/or set width: 100% so the section stacks vertically with the left
column (or switch the parent layout to flex-direction: column); ensure
ProductContentLayout content can scroll/expand on small screens to avoid
clipping.

Comment on lines +2 to +25
import anthropicLogo from "../../plugins/assets/llmWhisperer/Anthropic.svg";
import azureGptLogo from "../../plugins/assets/llmWhisperer/Azure GPT.png";
import llmG2Badge from "../../plugins/assets/llmWhisperer/G2-Badge.png";
import gdprBadge from "../../plugins/assets/llmWhisperer/GDPR.webp";
import gregCrisciPhoto from "../../plugins/assets/llmWhisperer/Greg Crisci.jpeg";
import hipaaBadge from "../../plugins/assets/llmWhisperer/HIPAA-1.png.webp";
import isoBadge from "../../plugins/assets/llmWhisperer/ISO-27001.png";
import openAiLogo from "../../plugins/assets/llmWhisperer/OpenAI-icon.svg";
import quoteIcon from "../../plugins/assets/llmWhisperer/quote-icon.svg";
import soc2Badge from "../../plugins/assets/llmWhisperer/SOC2-Type-II.png";
import statIconAccuracy from "../../plugins/assets/llmWhisperer/stat-icon-accuracy.svg";
import statIconManual from "../../plugins/assets/llmWhisperer/stat-icon-manual.svg";
import statIconTouchpoints from "../../plugins/assets/llmWhisperer/stat-icon-touchpoints.svg";
import vertexAiLogo from "../../plugins/assets/llmWhisperer/Vertex AI.svg";
import christopherVarnerPhoto from "../../plugins/assets/unstract/Christopher Varner.jpeg";
import cybersoftLogo from "../../plugins/assets/unstract/cybersoft.png";
import endpointClinicalLogo from "../../plugins/assets/unstract/endpoint-clinical.svg";
import unstractG2BadgeNew from "../../plugins/assets/unstract/G2-Badge-new.png";
import medaxionLogo from "../../plugins/assets/unstract/medaxion.svg";
import moodysLogo from "../../plugins/assets/unstract/moodys.png";
import unstractQuoteIcon from "../../plugins/assets/unstract/quote-icon.svg";
import unstractStatIconAccuracy from "../../plugins/assets/unstract/stat-icon-accuracy.svg";
import unstractStatIconEfficiency from "../../plugins/assets/unstract/stat-icon-efficiency.svg";
import unstractStatIconStp from "../../plugins/assets/unstract/stat-icon-stp.svg";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify that all imported asset files exist
echo "=== Checking for plugin asset directories ==="
echo ""

echo "Listing llmWhisperer assets directory:"
if [ -d "frontend/src/plugins/assets/llmWhisperer" ]; then
    ls -la "frontend/src/plugins/assets/llmWhisperer" 2>/dev/null | head -30 || echo "Directory exists but cannot list contents"
else
    echo "Directory not found: frontend/src/plugins/assets/llmWhisperer"
fi

echo ""
echo "Listing unstract assets directory:"
if [ -d "frontend/src/plugins/assets/unstract" ]; then
    ls -la "frontend/src/plugins/assets/unstract" 2>/dev/null | head -30 || echo "Directory exists but cannot list contents"
else
    echo "Directory not found: frontend/src/plugins/assets/unstract"
fi

echo ""
echo "=== Checking if assets path exists at all ==="
if [ -d "frontend/src/plugins" ]; then
    echo "frontend/src/plugins exists. Contents:"
    find frontend/src/plugins -type f 2>/dev/null | head -50
else
    echo "frontend/src/plugins does not exist"
fi

echo ""
echo "=== Checking frontend/src directory structure ==="
ls -la frontend/src/ 2>/dev/null | grep -E "^d"

Repository: Zipstack/unstract

Length of output: 1000


🏁 Script executed:

#!/bin/bash
# Search for the imported asset files
echo "=== Searching for imported asset files ==="
echo ""

# Search for specific files mentioned in imports
files_to_find=(
    "Anthropic.svg"
    "Azure GPT.png"
    "G2-Badge.png"
    "GDPR.webp"
    "Greg Crisci.jpeg"
    "HIPAA-1.png.webp"
    "ISO-27001.png"
    "OpenAI-icon.svg"
    "quote-icon.svg"
    "SOC2-Type-II.png"
    "stat-icon-accuracy.svg"
    "Christopher Varner.jpeg"
    "cybersoft.png"
    "endpoint-clinical.svg"
    "G2-Badge-new.png"
    "medaxion.svg"
    "moodys.png"
)

echo "Searching for asset files in the repository..."
for file in "${files_to_find[@]}"; do
    find . -name "$file" -type f 2>/dev/null
done

echo ""
echo "=== Contents of frontend/src/assets ==="
if [ -d "frontend/src/assets" ]; then
    find frontend/src/assets -type f | sort | head -50
else
    echo "frontend/src/assets not found"
fi

echo ""
echo "=== Search for any 'llmWhisperer' or 'unstract' directories ==="
find . -type d -name "llmWhisperer" -o -type d -name "unstract" 2>/dev/null

Repository: Zipstack/unstract

Length of output: 2645


🏁 Script executed:

#!/bin/bash
# Verify the file exists and contains these imports
echo "=== Checking ProductContentLayout.jsx ==="
if [ -f "frontend/src/components/log-in/ProductContentLayout.jsx" ]; then
    echo "File found. First 30 lines:"
    head -30 frontend/src/components/log-in/ProductContentLayout.jsx
else
    echo "File not found at frontend/src/components/log-in/ProductContentLayout.jsx"
    echo ""
    echo "Searching for ProductContentLayout.jsx:"
    find . -name "ProductContentLayout.jsx" -type f 2>/dev/null
fi

Repository: Zipstack/unstract

Length of output: 2239


These asset imports reference non-existent files and will cause immediate build failure.

All 24 imported asset files from ../../plugins/assets/llmWhisperer/ and ../../plugins/assets/unstract/ do not exist in the repository. The frontend/src/plugins/ directory structure does not exist at all. The component cannot build or run with these imports. Either commit the missing asset files to the correct paths or update the imports to point to existing assets in frontend/src/assets/.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/log-in/ProductContentLayout.jsx` around lines 2 - 25,
ProductContentLayout.jsx currently imports 24 asset modules (e.g.,
anthropicLogo, azureGptLogo, llmG2Badge, gregCrisciPhoto,
christopherVarnerPhoto, unstractQuoteIcon, etc.) from non-existent
../../plugins/assets/... paths which breaks the build; fix the imports in
ProductContentLayout.jsx by either (A) replacing each ../../plugins/assets/...
import with the correct existing paths under frontend/src/assets/ for the
matching files, or (B) removing/conditionally loading unused assets and
substituting available placeholders, ensuring all referenced symbols
(anthropicLogo, openAiLogo, statIconAccuracy, unstractStatIconEfficiency, etc.)
resolve to actual files or exports before committing.

Comment on lines +42 to +47
const DEFAULT_LLM_PROVIDERS = [
{ name: "Anthropic", logo: anthropicLogo },
{ name: "Azure GPT", logo: azureGptLogo },
{ name: "OpenAI", logo: openAiLogo },
{ name: "Vertex AI", logo: vertexAiLogo },
];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove duplicate constant arrays.

LLM_PROVIDERS (lines 133-138) is identical to DEFAULT_LLM_PROVIDERS (lines 42-47). Similarly:

  • TRUSTED_BY_LOGOSDEFAULT_TRUSTED_LOGOS
  • UNSTRACT_COMPLIANCE_BADGESDEFAULT_COMPLIANCE_BADGES

Reuse the existing constants to avoid drift and reduce bundle size.

♻️ Proposed fix: remove duplicates
-const LLM_PROVIDERS = [
-  { name: "Anthropic", logo: anthropicLogo },
-  { name: "Azure GPT", logo: azureGptLogo },
-  { name: "OpenAI", logo: openAiLogo },
-  { name: "Vertex AI", logo: vertexAiLogo },
-];
+// Reuse DEFAULT_LLM_PROVIDERS in LlmWhispererContent

-const TRUSTED_BY_LOGOS = [
-  { name: "Moody's", logo: moodysLogo },
-  { name: "Endpoint Clinical", logo: endpointClinicalLogo },
-  { name: "Cybersoft", logo: cybersoftLogo },
-  { name: "Medaxion", logo: medaxionLogo },
-];
+// Reuse DEFAULT_TRUSTED_LOGOS in UnstractContent

-const UNSTRACT_COMPLIANCE_BADGES = [
-  { name: "SOC2 Type II", logo: soc2Badge },
-  { name: "GDPR", logo: gdprBadge },
-  { name: "ISO", logo: isoBadge },
-  { name: "HIPAA", logo: hipaaBadge },
-  { name: "G2 Users Love Us", logo: unstractG2BadgeNew },
-];
+// Reuse DEFAULT_COMPLIANCE_BADGES in UnstractContent

Then update the component usages from LLM_PROVIDERSDEFAULT_LLM_PROVIDERS, etc.

Also applies to: 133-138

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/log-in/ProductContentLayout.jsx` around lines 42 -
47, There are duplicate constant arrays; remove the redundant definitions
(LLM_PROVIDERS, TRUSTED_BY_LOGOS, UNSTRACT_COMPLIANCE_BADGES) and update all
usages to reference the existing defaults (DEFAULT_LLM_PROVIDERS,
DEFAULT_TRUSTED_LOGOS, DEFAULT_COMPLIANCE_BADGES) so the component
(ProductContentLayout) and any other consumers import/use the single source of
truth—search for and replace references to LLM_PROVIDERS →
DEFAULT_LLM_PROVIDERS, TRUSTED_BY_LOGOS → DEFAULT_TRUSTED_LOGOS, and
UNSTRACT_COMPLIANCE_BADGES → DEFAULT_COMPLIANCE_BADGES, then delete the
now-unused duplicate constant declarations and remove any related unused
imports.

Auto-fix formatting issues (double quotes, semicolons, import ordering)
flagged by the biome-check CI workflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

Frontend Lint Report (Biome)

All checks passed! No linting or formatting issues found.

@sonarqubecloud
Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
frontend/src/components/log-in/Login.css (2)

267-290: Excessive !important usage in typography styles.

Multiple properties in .llm-headline (lines 284-290) and similar classes throughout use !important declarations. While this may be necessary to override Ant Design's default styles, consider using more specific selectors or scoped CSS modules to avoid specificity wars.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/log-in/Login.css` around lines 267 - 290, The CSS
uses excessive !important in the .llm-headline (and similar) rules which causes
specificity wars; remove the unnecessary !important flags and instead increase
selector specificity or scope the rules (e.g., target .llm-whisperer-content
.llm-headline or convert to a CSS module/scoped stylesheet) so these typography
styles override Ant Design without !important; update the selectors for
.llm-headline and related classes and verify the visual result across
breakpoints.

384-411: Consider CSS custom properties to reduce duplication.

The .llm-stats-bar and .unstract-stats-bar (and their child classes) share nearly identical styles. Using CSS custom properties for colors and spacing would reduce duplication and make theme-wide changes easier.

Example approach
/* Define theme tokens */
.llm-whisperer-dark {
  --stat-value-color: `#fff`;
  --stat-label-color: `#d1d5dc`;
}

.unstract-light {
  --stat-value-color: `#282828`;
  --stat-label-color: `#545454`;
}

/* Shared stat styles */
.stat-value {
  font-size: 22px;
  font-weight: 600;
  color: var(--stat-value-color);
}

Also applies to: 562-589

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/log-in/Login.css` around lines 384 - 411, Extract
duplicated styling from .llm-stats-bar/.unstract-stats-bar and their children by
introducing shared utility classes (e.g., .stats-bar, .stat-item, .stat-value,
.stat-label) and move common rules (display, gap, alignment, font-size,
font-weight, layout) into those; define theme tokens as CSS custom properties on
the theme roots (.llm-whisperer-dark, .unstract-light) such as
--stat-value-color and --stat-label-color and replace hardcoded color values in
.stat-value and .stat-label with
var(--stat-value-color)/var(--stat-label-color); update references to
.llm-stat-item/.llm-stat-value/.llm-stat-label and
.llm-stats-bar/.unstract-stats-bar to use the new shared classes so spacing and
color changes can be done via the theme variables (also apply same refactor to
the other duplicated block at lines 562-589).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/src/components/log-in/Login.css`:
- Around line 869-909: The .region-option buttons lack keyboard focus
indicators; add explicit :focus and :focus-visible rules for .region-option (and
optionally for .region-option-selected) to show a clear visible outline or
box-shadow (e.g., a high-contrast ring or outline with outline-offset) that does
not disturb layout, ensure the focus styles are applied to the clickable element
and not just the image (reference the .region-option, .region-option:focus,
.region-option:focus-visible and .region-option-selected .region-flag selectors)
and keep the visual treatment consistent with the existing accent color and
rounded flag (use border-radius and appropriate contrast).
- Around line 822-843: The toggle buttons (.product-toggle-btn and
.product-toggle-btn-active) lack keyboard focus styling; add :focus and/or
:focus-visible rules for both selectors to provide a visible outline or enhanced
box-shadow and ensure the focus style is distinct from hover/active (e.g., a
high-contrast outline or ring color that matches your design), keep existing
border-radius and avoid removing focus on click, and ensure focus styles meet
contrast/accessibility requirements so keyboard users can clearly see which
product is focused.

---

Nitpick comments:
In `@frontend/src/components/log-in/Login.css`:
- Around line 267-290: The CSS uses excessive !important in the .llm-headline
(and similar) rules which causes specificity wars; remove the unnecessary
!important flags and instead increase selector specificity or scope the rules
(e.g., target .llm-whisperer-content .llm-headline or convert to a CSS
module/scoped stylesheet) so these typography styles override Ant Design without
!important; update the selectors for .llm-headline and related classes and
verify the visual result across breakpoints.
- Around line 384-411: Extract duplicated styling from
.llm-stats-bar/.unstract-stats-bar and their children by introducing shared
utility classes (e.g., .stats-bar, .stat-item, .stat-value, .stat-label) and
move common rules (display, gap, alignment, font-size, font-weight, layout) into
those; define theme tokens as CSS custom properties on the theme roots
(.llm-whisperer-dark, .unstract-light) such as --stat-value-color and
--stat-label-color and replace hardcoded color values in .stat-value and
.stat-label with var(--stat-value-color)/var(--stat-label-color); update
references to .llm-stat-item/.llm-stat-value/.llm-stat-label and
.llm-stats-bar/.unstract-stats-bar to use the new shared classes so spacing and
color changes can be done via the theme variables (also apply same refactor to
the other duplicated block at lines 562-589).

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to Reviews > Disable Cache setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between b9cf878 and 8e965bd.

📒 Files selected for processing (2)
  • frontend/src/components/log-in/Login.css
  • frontend/vite.config.js

Comment on lines +822 to +843
.product-toggle-btn {
flex: 1;
height: 39px;
border: none;
border-radius: 16px;
background: transparent;
font-size: 11px;
font-weight: 900;
letter-spacing: 0.6px;
text-transform: uppercase;
color: #90a1b9;
cursor: pointer;
transition: all 0.2s ease;
font-family: inherit;
}

.product-toggle-btn-active {
background: #fff;
color: #2f93f6;
border: 1px solid #f1f5f9;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add focus styles for product toggle buttons.

The .product-toggle-btn lacks :focus or :focus-visible styles. Keyboard users switching between Unstract and LLMWhisperer won't have clear visual feedback.

Suggested addition
 .product-toggle-btn {
   flex: 1;
   height: 39px;
   border: none;
   border-radius: 16px;
   background: transparent;
   font-size: 11px;
   font-weight: 900;
   letter-spacing: 0.6px;
   text-transform: uppercase;
   color: `#90a1b9`;
   cursor: pointer;
   transition: all 0.2s ease;
   font-family: inherit;
 }

+.product-toggle-btn:focus-visible {
+  outline: 2px solid `#2f93f6`;
+  outline-offset: 2px;
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.product-toggle-btn {
flex: 1;
height: 39px;
border: none;
border-radius: 16px;
background: transparent;
font-size: 11px;
font-weight: 900;
letter-spacing: 0.6px;
text-transform: uppercase;
color: #90a1b9;
cursor: pointer;
transition: all 0.2s ease;
font-family: inherit;
}
.product-toggle-btn-active {
background: #fff;
color: #2f93f6;
border: 1px solid #f1f5f9;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.product-toggle-btn {
flex: 1;
height: 39px;
border: none;
border-radius: 16px;
background: transparent;
font-size: 11px;
font-weight: 900;
letter-spacing: 0.6px;
text-transform: uppercase;
color: `#90a1b9`;
cursor: pointer;
transition: all 0.2s ease;
font-family: inherit;
}
.product-toggle-btn:focus-visible {
outline: 2px solid `#2f93f6`;
outline-offset: 2px;
}
.product-toggle-btn-active {
background: `#fff`;
color: `#2f93f6`;
border: 1px solid `#f1f5f9`;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/log-in/Login.css` around lines 822 - 843, The toggle
buttons (.product-toggle-btn and .product-toggle-btn-active) lack keyboard focus
styling; add :focus and/or :focus-visible rules for both selectors to provide a
visible outline or enhanced box-shadow and ensure the focus style is distinct
from hover/active (e.g., a high-contrast outline or ring color that matches your
design), keep existing border-radius and avoid removing focus on click, and
ensure focus styles meet contrast/accessibility requirements so keyboard users
can clearly see which product is focused.

Comment on lines +869 to +909
.region-option {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 0;
border: none;
background: transparent;
cursor: pointer;
position: relative;
}

.region-flag {
width: 58px;
height: 58px;
border-radius: 50%;
object-fit: cover;
}

.region-option-selected .region-flag {
box-shadow: 0 0 0 3px #2f93f6;
border-radius: 50%;
}

.region-label {
font-size: 18px;
font-weight: 500;
color: #545454;
}

.region-radio-indicator {
position: absolute;
top: -4px;
right: -4px;
width: 16px;
height: 16px;
border-radius: 50%;
background: #2f93f6;
border: 3px solid #fff;
box-shadow: 0 0 0 1px #2f93f6;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add focus styles for keyboard accessibility.

The .region-option button lacks explicit :focus or :focus-visible styles. Keyboard users navigating the region selector may not see clear focus indicators.

Suggested addition
 .region-option {
   display: flex;
   flex-direction: column;
   align-items: center;
   gap: 8px;
   padding: 0;
   border: none;
   background: transparent;
   cursor: pointer;
   position: relative;
 }

+.region-option:focus-visible .region-flag {
+  box-shadow: 0 0 0 3px `#2f93f6`;
+  outline: 2px solid transparent;
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/log-in/Login.css` around lines 869 - 909, The
.region-option buttons lack keyboard focus indicators; add explicit :focus and
:focus-visible rules for .region-option (and optionally for
.region-option-selected) to show a clear visible outline or box-shadow (e.g., a
high-contrast ring or outline with outline-offset) that does not disturb layout,
ensure the focus styles are applied to the clickable element and not just the
image (reference the .region-option, .region-option:focus,
.region-option:focus-visible and .region-option-selected .region-flag selectors)
and keep the visual treatment consistent with the existing accent color and
rounded flag (use border-radius and appropriate contrast).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants