-
Notifications
You must be signed in to change notification settings - Fork 776
feat(route): redesign /mock-interview with Forge AI-inspired landing #4404
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| import React from 'react'; | ||
|
|
||
| /** | ||
| * Hover-glow bento card. Tracks cursor for the radial glow (forge signature). | ||
| */ | ||
| export default function BentoCard({ icon: Icon, title, description, className = '' }) { | ||
| const onMove = (e) => { | ||
| const r = e.currentTarget.getBoundingClientRect(); | ||
| e.currentTarget.style.setProperty('--mx', `${e.clientX - r.left}px`); | ||
| e.currentTarget.style.setProperty('--my', `${e.clientY - r.top}px`); | ||
| }; | ||
| return ( | ||
| <div className={`forge-card ${className}`} onMouseMove={onMove}> | ||
| {Icon && ( | ||
| <div className="ico"> | ||
| <Icon size={22} strokeWidth={1.8} /> | ||
| </div> | ||
| )} | ||
| <h3>{title}</h3> | ||
| <p>{description}</p> | ||
| </div> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import React from 'react'; | ||
| import { Link } from 'react-router-dom'; | ||
|
|
||
| /** Forge button — renders as router Link or anchor. */ | ||
| export default function ForgeButton({ to, href, children, variant = 'primary', ...rest }) { | ||
| const cls = `forge-btn ${variant === 'primary' ? 'forge-btn-primary' : 'forge-btn-ghost'}`; | ||
| if (to) return <Link to={to} className={cls} {...rest}>{children}</Link>; | ||
| return <a href={href || '#'} className={cls} {...rest}>{children}</a>; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Using a raw anchor for the Severity Level: Major
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,166 @@ | ||
| import React from 'react'; | ||
| import { Link } from 'react-router-dom'; | ||
| import { useAuth } from '../../hooks/useAuth'; | ||
| import { FEATURES_BY_SLUG } from '../../data/featuresConfig'; | ||
| import Seo from '../../components/Seo'; | ||
| import '../styles/forge.css'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: This relative CSS import points to a non-existent Severity Level: Critical 🚨- ❌ Forge feature routes fail to compile due to CSS.
- ❌ /mock-interview Forge landing cannot load at all.
- ⚠️ Future ForgeFeaturePage usages blocked until import fixed.Steps of Reproduction ✅1. Open frontend/src/pages/features/MockInterviewForge.jsx, which imports ForgeFeaturePage
from '../../components/forge/ForgeFeaturePage at lines 2-4 and is itself lazily imported
as MockInterviewLanding in frontend/src/App.jsx at line 111.
2. Inspect frontend/src/components/forge/ForgeFeaturePage.jsx where the ForgeFeaturePage
component is defined; line 6 imports '../styles/forge.css'.
3. From the ForgeFeaturePage.jsx location (frontend/src/components/forge), the relative
import '../styles/forge.css' resolves to frontend/src/components/styles/forge.css.
4. LS output for frontend/src/styles shows forge.css lives at
frontend/src/styles/forge.css and LS for frontend/src/components shows no styles
directory, so any build that compiles ForgeFeaturePage (e.g., when loading the
/mock-interview feature route) will fail with a module-not-found error for
'../styles/forge.css'.(Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** frontend/src/components/forge/ForgeFeaturePage.jsx
**Line:** 6:6
**Comment:**
*Import Error: This relative CSS import points to a non-existent `components/styles` directory from this file location, so the module cannot be resolved at build/runtime. Update the path to the actual `src/styles/forge.css` location.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix |
||
| import StatusBadge from './forge/StatusBadge'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: This import adds an extra Severity Level: Critical 🚨- ❌ All ForgeFeaturePage-based routes crash on import error.
- ❌ /mock-interview Forge landing unusable in production.
- ⚠️ StatusBadge component cannot be reused in Forge page.Steps of Reproduction ✅1. Inspect frontend/src/pages/features/MockInterviewForge.jsx where MockInterviewForge
returns ForgeFeaturePage with slug "mock-interview" (lines 2-4); this page is wired into
AppRoutes via the lazy import MockInterviewLanding in frontend/src/App.jsx at line 111.
2. In frontend/src/components/forge/ForgeFeaturePage.jsx, note line 7 imports StatusBadge
from './forge/StatusBadge'.
3. From the directory frontend/src/components/forge, the path './forge/StatusBadge'
resolves to frontend/src/components/forge/forge/StatusBadge.jsx.
4. LS output for frontend/src/components/forge shows only BentoCard.jsx, ForgeButton.jsx,
ForgeFeaturePage.jsx, MetricChip.jsx, and StatusBadge.jsx at the top level, with no forge
subdirectory, so bundling ForgeFeaturePage for any feature route (mock-interview,
resume-builder, project-visualizer, resume-roast, github-portfolio via the imports found
by Grep) will throw a "Module not found: './forge/StatusBadge'" error.(Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** frontend/src/components/forge/ForgeFeaturePage.jsx
**Line:** 7:7
**Comment:**
*Import Error: This import adds an extra `forge/` segment even though `StatusBadge` is in the same directory, so bundling fails with a missing module error. Import directly from the sibling file path.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix |
||
| import MetricChip from './forge/MetricChip'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: This relative import points to Severity Level: Critical 🚨- ❌ Forge feature heroes cannot render metric chips.
- ❌ Multiple feature landing pages fail during compilation.
- ⚠️ Stats display broken, degrading feature marketing UX.Steps of Reproduction ✅1. From Grep results, confirm ForgeFeaturePage is imported by multiple feature pages
(frontend/src/pages/features/ResumeBuilderForge.jsx, ProjectVisualizerForge.jsx,
ResumeRoastForge.jsx, MockInterviewForge.jsx, GithubPortfolioForge.jsx), so it is on
several landing routes.
2. Open frontend/src/components/forge/ForgeFeaturePage.jsx and observe line 8 importing
MetricChip from './forge/MetricChip'.
3. From the file’s directory frontend/src/components/forge, the './forge/MetricChip' path
resolves to frontend/src/components/forge/forge/MetricChip.jsx.
4. LS output for frontend/src/components/forge shows MetricChip.jsx exists as a sibling in
that directory, with no forge subfolder, so when the bundler compiles ForgeFeaturePage for
any of the Forge feature routes it will fail with "Module not found: './forge/MetricChip'"
and prevent those pages from loading.(Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** frontend/src/components/forge/ForgeFeaturePage.jsx
**Line:** 8:8
**Comment:**
*Import Error: This relative import points to `components/forge/forge/MetricChip`, which does not exist, causing a hard import failure. Change it to the correct same-folder path.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix |
||
| import ForgeButton from './forge/ForgeButton'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: This import incorrectly references a Severity Level: Critical 🚨- ❌ Primary CTA buttons on Forge features fail to render.
- ❌ Build may halt due to missing ForgeButton module.
- ⚠️ User onboarding flows via Forge landings disrupted.Steps of Reproduction ✅1. Verify via LS that frontend/src/components/forge contains ForgeButton.jsx as a sibling
file, with no nested forge directory.
2. In frontend/src/components/forge/ForgeFeaturePage.jsx, note line 9 imports ForgeButton
from './forge/ForgeButton'.
3. From the ForgeFeaturePage.jsx location (frontend/src/components/forge),
'./forge/ForgeButton' resolves to a non-existent path
frontend/src/components/forge/forge/ForgeButton.jsx.
4. During bundling of ForgeFeaturePage (invoked by feature pages such as
MockInterviewForge.jsx and others listed by Grep), module resolution for
'./forge/ForgeButton' will fail, breaking primary and secondary CTA buttons on all Forge
feature landings and potentially stopping the build.(Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** frontend/src/components/forge/ForgeFeaturePage.jsx
**Line:** 9:9
**Comment:**
*Import Error: This import incorrectly references a `forge` subfolder under the current `forge` directory, so the file cannot be found. Point it to the sibling `ForgeButton` file.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix |
||
| import BentoCard from './forge/BentoCard'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: This import path is incorrect for a sibling component and resolves to a non-existent location, which will break compilation. Use the direct local path to Severity Level: Critical 🚨- ❌ Forge capabilities bento grid cannot render at all.
- ❌ All ForgeFeaturePage landings risk build-time failure.
- ⚠️ Feature demos and showcases unavailable to end users.Steps of Reproduction ✅1. Confirm via BulkRead that BentoCard.jsx is defined in
frontend/src/components/forge/BentoCard.jsx, exporting the BentoCard component (lines
3-23).
2. In frontend/src/components/forge/ForgeFeaturePage.jsx, line 10 imports BentoCard from
'./forge/BentoCard'.
3. Given ForgeFeaturePage.jsx resides in frontend/src/components/forge, the
'./forge/BentoCard' import resolves to frontend/src/components/forge/forge/BentoCard.jsx,
which does not exist per LS output.
4. When ForgeFeaturePage is compiled for any feature route (ResumeBuilderForge,
ProjectVisualizerForge, ResumeRoastForge, GithubPortfolioForge, MockInterviewForge), the
bundler will raise a module-not-found error for './forge/BentoCard', breaking the
capabilities bento section and potentially failing the entire build.(Use Cmd/Ctrl + Click for best experience) Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** frontend/src/components/forge/ForgeFeaturePage.jsx
**Line:** 10:10
**Comment:**
*Import Error: This import path is incorrect for a sibling component and resolves to a non-existent location, which will break compilation. Use the direct local path to `BentoCard`.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix |
||
|
|
||
| const ICONS = { | ||
| FileText: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z M14 2v6h6', | ||
| Type: 'M4 7V4h16v3 M9 20h6 M12 4v16', | ||
| Github: 'M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22', | ||
| Sparkles: 'M12 3v3 M12 18v3 M3 12h3 M18 12h3 M5.6 5.6l2.1 2.1 M16.3 16.3l2.1 2.1 M18.4 5.6l-2.1 2.1 M7.7 16.3l-2.1 2.1', | ||
| BarChart: 'M3 3v18h18 M8 17V9 M13 17V5 M18 17v-6', | ||
| Layout: 'M3 3h18v18H3z M3 9h18 M9 21V9', | ||
| Linkedin: 'M4 4a2 2 0 1 0 0 4 2 2 0 0 0 0-4z M4 9h4v11H4z M10 9h4v3a4 4 0 0 1 8 0v8h-4v-7a2 2 0 0 0-4 0v7h-4z', | ||
| Download: 'M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4 M7 10l5 5 5-5 M12 15V3', | ||
| Mic: 'M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z M19 10v2a7 7 0 0 1-14 0v-2 M12 19v4 M8 23h8', | ||
| Briefcase: 'M2 7h20v13H2z M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16', | ||
| Flame: 'M12 2s4 4 4 8a4 4 0 0 1-8 0c0-1 .5-2 1-3-2 1-4 3-4 6a7 7 0 0 0 14 0c0-5-7-11-7-11z', | ||
| Network: 'M12 2a3 3 0 1 0 0 6 3 3 0 0 0 0-6z M5 16a3 3 0 1 0 0 6 3 3 0 0 0 0-6z M19 16a3 3 0 1 0 0 6 3 3 0 0 0 0-6z M7 18l3-7 M17 18l-3-7 M8 19h8', | ||
| Users: 'M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2 M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z M23 21v-2a4 4 0 0 0-3-3.87 M16 3.13a4 4 0 0 1 0 7.75', | ||
| Palette: 'M12 2a9 9 0 0 0 0 18c1.1 0 2-.9 2-2 0-.5-.2-1-.5-1.3-.3-.4-.5-.8-.5-1.2 0-1 .8-1.8 1.8-1.8H17a4 4 0 0 0 4-4c0-4.4-4-8-9-8z M7.5 11.5A1 1 0 1 0 7 13a1 1 0 0 0 .5-1.5z M12 7.5A1 1 0 1 0 12.5 9 1 1 0 0 0 12 7.5z', | ||
| Zap: 'M13 2L3 14h9l-1 8 10-12h-9z', | ||
| Smartphone: 'M7 2h10a2 2 0 0 1 2 2v16a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2z M12 18h.01', | ||
| Globe: 'M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20z M2 12h20 M12 2a15 15 0 0 1 0 20 M12 2a15 15 0 0 0 0 20', | ||
| }; | ||
|
|
||
| function Icon({ name, size = 22, strokeWidth = 1.8 }) { | ||
| const d = ICONS[name]; | ||
| if (!d) return null; | ||
| return ( | ||
| <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={strokeWidth} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"> | ||
| {d.split(' M').map((seg, i) => ( | ||
| <path key={i} d={(i === 0 ? seg : 'M' + seg)} /> | ||
| ))} | ||
| </svg> | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * ForgeFeaturePage — data-driven landing for a single feature route. | ||
| * Reads the existing FEATURES_BY_SLUG[slug] config and renders a cohesive, | ||
| * forge-ai-inspired page (status chips, monospace metrics, bento showcase, steps). | ||
| * Each route landing imports this with its slug. | ||
| */ | ||
| export default function ForgeFeaturePage({ slug }) { | ||
| const { user } = useAuth(); | ||
| const config = FEATURES_BY_SLUG[slug]; | ||
| if (!config) return <div className="forge-page">Unknown feature: {slug}</div>; | ||
|
|
||
| const heroCtaText = user ? config.primaryAction.label : config.hero.primaryCta.text; | ||
| const heroCtaLink = user ? config.primaryAction.to : config.hero.primaryCta.to; | ||
| const ctaText = user ? config.primaryAction.label : config.cta.ctaText; | ||
| const ctaLink = user ? config.primaryAction.to : config.cta.ctaTo; | ||
|
|
||
| return ( | ||
| <div className="forge-page"> | ||
| <Seo {...config.seo} /> | ||
|
|
||
| <nav className="forge-nav"> | ||
| <Link to="/" className="forge-brand">CareerPilot<span className="dot">.</span></Link> | ||
| <div className="forge-nav-links"> | ||
| <Link to="/resume-builder" className="forge-nav-link">Resume Builder</Link> | ||
| <Link to="/portfolio-builder" className="forge-nav-link">Portfolio</Link> | ||
| <Link to="/job-finder" className="forge-nav-link">Job Finder</Link> | ||
| <Link to="/mock-interview" className="forge-nav-link">Mock Interview</Link> | ||
| </div> | ||
| <div className="forge-nav-actions"> | ||
| {!user && <ForgeButton href="/login" variant="ghost">Sign in</ForgeButton>} | ||
| <ForgeButton to={heroCtaLink} variant="primary">{user ? 'Dashboard' : 'Get started for free'}</ForgeButton> | ||
| </div> | ||
| </nav> | ||
|
|
||
| {/* HERO */} | ||
| <section className="forge-section forge-container forge-hero"> | ||
| <StatusBadge label="OPERATIONAL" /> | ||
| <h1> | ||
| {config.hero.title} <span className="accent">{config.hero.accentText}</span> | ||
| </h1> | ||
| <p>{config.hero.description}</p> | ||
| <div className="forge-hero-actions"> | ||
| <ForgeButton to={heroCtaLink} variant="primary">{heroCtaText}</ForgeButton> | ||
| {config.hero.secondaryCta && ( | ||
| <ForgeButton href={config.hero.secondaryCta.href} variant="ghost">{config.hero.secondaryCta.text}</ForgeButton> | ||
| )} | ||
| </div> | ||
| <div className="forge-metrics"> | ||
| {config.hero.stats.map((s, i) => ( | ||
| <MetricChip key={i} value={s.value} label={s.label} accent={i === 0} /> | ||
| ))} | ||
| </div> | ||
| </section> | ||
|
|
||
| {/* SHOWCASE */} | ||
| {config.showcase && ( | ||
| <section className="forge-section forge-container" id="demo"> | ||
| <div style={{ textAlign: 'center' }}> | ||
| <span className="forge-label">Capabilities</span> | ||
| <h2 className="forge-h2">{config.showcase.heading}</h2> | ||
| </div> | ||
| <div className="forge-bento"> | ||
| {config.showcase.features.map((f, i) => ( | ||
| <BentoCard key={i} icon={(p) => <Icon name={f.icon} {...p} />} title={f.title} description={f.description} /> | ||
| ))} | ||
| </div> | ||
| </section> | ||
| )} | ||
|
|
||
| {/* HOW IT WORKS */} | ||
| {config.howItWorks && ( | ||
| <section className="forge-section forge-container"> | ||
| <div style={{ textAlign: 'center' }}> | ||
| <span className="forge-label">Workflow</span> | ||
| <h2 className="forge-h2">{config.howItWorks.title}</h2> | ||
| </div> | ||
| <div className="forge-steps"> | ||
| {config.howItWorks.steps.map((s, i) => ( | ||
| <div key={i} className="forge-step"> | ||
| <span className="n">STEP {s.number}</span> | ||
| <h4>{s.title}</h4> | ||
| <p>{s.description}</p> | ||
| </div> | ||
| ))} | ||
| </div> | ||
| </section> | ||
| )} | ||
|
|
||
| {/* TESTIMONIALS */} | ||
| {config.testimonials && config.testimonials.items?.length > 0 && ( | ||
| <section className="forge-section forge-container"> | ||
| <div style={{ textAlign: 'center' }}> | ||
| <span className="forge-label">Signal</span> | ||
| <h2 className="forge-h2">{config.testimonials.heading}</h2> | ||
| </div> | ||
| {config.testimonials.items.map((t, i) => ( | ||
| <div key={i} className="forge-quote"> | ||
| <p className="q">“{t.quote}”</p> | ||
| <div className="who"> | ||
| {t.avatar && <img src={t.avatar} alt="" width="36" height="36" style={{ borderRadius: '50%' }} />} | ||
| <span><strong style={{ color: 'var(--forge-text)' }}>{t.name}</strong> · {t.role}{t.company ? ` @ ${t.company}` : ''}</span> | ||
| <span className="metric" style={{ marginLeft: 'auto' }}>{t.metric}</span> | ||
| </div> | ||
| </div> | ||
| ))} | ||
| </section> | ||
| )} | ||
|
|
||
| {/* CTA */} | ||
| <section className="forge-container"> | ||
| <div className="forge-cta"> | ||
| <h2>{config.cta.headline}</h2> | ||
| <p>{config.cta.subtext}</p> | ||
| <ForgeButton to={ctaLink} variant="primary">{ctaText}</ForgeButton> | ||
| </div> | ||
| </section> | ||
|
|
||
| <footer className="forge-foot"> | ||
| CareerPilot · {config.name} · built with the Forge design system | ||
| </footer> | ||
| </div> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import React from 'react'; | ||
|
|
||
| /** Monospace metric chip used in hero stat rows. */ | ||
| export default function MetricChip({ value, label, accent = false }) { | ||
| return ( | ||
| <div className="forge-metric"> | ||
| <div className={`v ${accent ? 'accent' : ''}`}>{value}</div> | ||
| <div className="l">{label}</div> | ||
| </div> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import React from 'react'; | ||
|
|
||
| /** | ||
| * Forge signature status chip — operational/SLA style pill. | ||
| * variant: 'ok' | 'warn' | 'danger' | ||
| */ | ||
| export default function StatusBadge({ label = 'OPERATIONAL', variant = 'ok', className = '' }) { | ||
| const v = variant === 'danger' ? 'danger' : variant === 'warn' ? 'warn' : 'ok'; | ||
| return ( | ||
| <span className={`forge-status ${v} ${className}`}> | ||
| <span className="pulse" /> | ||
| {label} | ||
| </span> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| import React from 'react'; | ||
| import { motion } from 'framer-motion'; | ||
| import { FEATURES } from '../../data/featuresConfig'; | ||
| import '../styles/forge.css'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: This stylesheet import resolves to Severity Level: Major
|
||
| import StatusBadge from '../forge/StatusBadge'; | ||
| import ForgeButton from '../forge/ForgeButton'; | ||
|
|
||
| const ICON_PATHS = { | ||
| FileText: 'M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z M14 2v6h6', | ||
| Palette: 'M12 2a9 9 0 0 0 0 18c1.1 0 2-.9 2-2 0-.5-.2-1-.5-1.3-.3-.4-.5-.8-.5-1.2 0-1 .8-1.8 1.8-1.8H17a4 4 0 0 0 4-4c0-4.4-4-8-9-8z M7.5 11.5A1 1 0 1 0 7 13a1 1 0 0 0 .5-1.5z M12 7.5A1 1 0 1 0 12.5 9 1 1 0 0 0 12 7.5z', | ||
| Flame: 'M12 2s4 4 4 8a4 4 0 0 1-8 0c0-1 .5-2 1-3-2 1-4 3-4 6a7 7 0 0 0 14 0c0-5-7-11-7-11z', | ||
| Github: 'M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22', | ||
| Network: 'M12 2a3 3 0 1 0 0 6 3 3 0 0 0 0-6z M5 16a3 3 0 1 0 0 6 3 3 0 0 0 0-6z M19 16a3 3 0 1 0 0 6 3 3 0 0 0 0-6z M7 18l3-7 M17 18l-3-7 M8 19h8', | ||
| Mic: 'M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z M19 10v2a7 7 0 0 1-14 0v-2 M12 19v4 M8 23h8', | ||
| Users: 'M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2 M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z M23 21v-2a4 4 0 0 0-3-3.87 M16 3.13a4 4 0 0 1 0 7.75', | ||
| Briefcase: 'M2 7h20v13H2z M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16', | ||
| }; | ||
|
|
||
| const header = { hidden: {}, show: { transition: { staggerChildren: 0.12 } } }; | ||
| const item = { | ||
| hidden: { opacity: 0, y: 24 }, | ||
| show: { opacity: 1, y: 0, transition: { duration: 0.6, ease: [0.16, 1, 0.3, 1] } }, | ||
| }; | ||
|
|
||
| export default function ForgeToolsSection() { | ||
| return ( | ||
| <section className="forge-page" style={{ padding: '84px 0' }}> | ||
| <div className="forge-container"> | ||
| <motion.div | ||
| variants={header} | ||
| initial="hidden" | ||
| whileInView="show" | ||
| viewport={{ once: true, margin: '-100px' }} | ||
| style={{ textAlign: 'center' }} | ||
| > | ||
| <motion.div variants={item} style={{ display: 'flex', justifyContent: 'center', marginBottom: 18 }}> | ||
| <StatusBadge label="ALL SYSTEMS OPERATIONAL" /> | ||
| </motion.div> | ||
| <motion.h2 variants={item} className="forge-h2"> | ||
| Powerful AI tools for <span style={{ color: 'var(--forge-accent)' }}>every step</span> | ||
| </motion.h2> | ||
| <motion.p variants={item} className="forge-sub"> | ||
| From your first resume draft to your final interview, CareerPilot gives you the unfair advantage you need. | ||
| </motion.p> | ||
| </motion.div> | ||
|
|
||
| <div className="forge-tools-grid" style={{ marginTop: 44 }}> | ||
| {FEATURES.map((f, i) => { | ||
| const Icon = (p) => ( | ||
| <svg width={24} height={24} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.8} strokeLinecap="round" strokeLinejoin="round" {...p}> | ||
| {(ICON_PATHS[f.icon?.name] || ICON_PATHS.FileText).split(' M').map((seg, k) => ( | ||
| <path key={k} d={k === 0 ? seg : 'M' + seg} /> | ||
| ))} | ||
| </svg> | ||
| ); | ||
| const large = f.size === 'large'; | ||
| return ( | ||
| <motion.div | ||
| key={f.slug} | ||
| variants={item} | ||
| className={`forge-tool ${large ? 'lg' : ''}`} | ||
| style={large ? { display: 'flex', flexDirection: 'column', justifyContent: 'space-between' } : {}} | ||
| > | ||
| <div className="ico"><Icon /></div> | ||
| <div> | ||
| <span className="badge-tag">{f.badge || 'Tool'}</span> | ||
| <h3>{f.name}</h3> | ||
| <p>{f.tagline}</p> | ||
| </div> | ||
| <div style={{ marginTop: 18 }}> | ||
| <ForgeButton to={f.primaryAction.to} variant="ghost">{f.primaryAction.label} →</ForgeButton> | ||
| </div> | ||
| </motion.div> | ||
| ); | ||
| })} | ||
| </div> | ||
| </div> | ||
| </section> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import React from 'react'; | ||
| import ForgeFeaturePage from '../../components/forge/ForgeFeaturePage'; | ||
| export default function GithubPortfolioForge() { | ||
| return <ForgeFeaturePage slug="github-portfolio" />; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import React from 'react'; | ||
| import ForgeFeaturePage from '../../components/forge/ForgeFeaturePage'; | ||
| export default function MockInterviewForge() { | ||
| return <ForgeFeaturePage slug="mock-interview" />; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import React from 'react'; | ||
| import ForgeFeaturePage from '../../components/forge/ForgeFeaturePage'; | ||
| export default function ProjectVisualizerForge() { | ||
| return <ForgeFeaturePage slug="project-visualizer" />; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import React from 'react'; | ||
| import ForgeFeaturePage from '../../components/forge/ForgeFeaturePage'; | ||
| export default function ResumeBuilderForge() { | ||
| return <ForgeFeaturePage slug="resume-builder" />; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import React from 'react'; | ||
| import ForgeFeaturePage from '../../components/forge/ForgeFeaturePage'; | ||
| export default function ResumeRoastForge() { | ||
| return <ForgeFeaturePage slug="resume-roast" />; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: The route now lazy-loads the Forge implementation, but that module currently depends on
ForgeFeaturePage, which imports subcomponents using./forge/...paths that do not exist from its directory. As soon as/mock-interviewis loaded, this can fail module resolution and break the page load. Either switch back to the stable landing component or fix theForgeFeaturePageimport paths before wiring this route toMockInterviewForge. [import error]Severity Level: Critical 🚨
Steps of Reproduction ✅
(Use Cmd/Ctrl + Click for best experience)
Prompt for AI Agent 🤖