Skip to content

Integrate J-Space UI into QCX Dashboard#570

Open
ngoiyaeric wants to merge 1 commit intomainfrom
feature/j-space-ui-integration
Open

Integrate J-Space UI into QCX Dashboard#570
ngoiyaeric wants to merge 1 commit intomainfrom
feature/j-space-ui-integration

Conversation

@ngoiyaeric
Copy link
Collaborator

@ngoiyaeric ngoiyaeric commented Mar 14, 2026

This PR replaces the current dashboard design with the J-Space Windows 98-style UI, including all necessary assets and dependencies.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a Windows-98 style personal space interface featuring resizable windows for About Me, Skills, and Projects sections.
  • Refactor

    • Simplified the root layout by removing header, footer, and sidebar from the main page structure.

@vercel
Copy link
Contributor

vercel bot commented Mar 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
qcx Error Error Mar 14, 2026 6:14pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 14, 2026

Walkthrough

This PR replaces the existing AI chat-based layout with a retro Windows-98 themed portfolio interface. It removes header, footer, and sidebar components from the root layout, simplifies the page structure, introduces static portfolio content, and adds a new JSpaceUI component with resizable windows for displaying about me, skills, and projects information.

Changes

Cohort / File(s) Summary
Layout & Page Restructuring
app/layout.tsx, app/page.tsx
Commented out Header, Footer, and HistorySidebar components from root layout. Replaced AI provider wrapping and chat initialization in page.tsx with direct JSpaceUI component rendering.
Portfolio Content Data
components/j-space-content.ts
New static content object exporting personal information (aboutMe), skill sets, and project entries with metadata (title, description, image, links).
Windows-98 UI Component
components/j-space-ui.tsx
New React component rendering a retro desktop UI with dynamically loaded 98-components library. Includes three resizable windows (About Me, Skills, Projects) with inline styling, image URL resolution, and taskbar placeholder.
Dependency Additions
package.json
Added "98-components" (^0.1.1) and "98.css" (^0.1.21) dependencies for retro UI styling and component library.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

Review effort 3/5

Poem

🐰 A Windows-98 dream takes flight,
With resizable panes shining bright,
Portfolio windows, skills on display,
Retro chic leads the way! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: integrating J-Space UI into the QCX Dashboard. This is clearly reflected in the file changes, particularly the new J-Space UI component and layout modifications.

✏️ 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/j-space-ui-integration
📝 Coding Plan
  • Generate coding plan for human review comments

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.

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: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/layout.tsx`:
- Around line 7-9: Remove the dead commented-out layout branches in
app/layout.tsx by deleting the unused commented import lines referencing Header,
Footer, and Sidebar and any corresponding commented render sites (including the
block noted around lines 112-116); ensure no other code relies on those
commented placeholders and keep the active layout imports/JSX only so the file
contains only actual imports and render logic.

In `@app/page.tsx`:
- Around line 7-8: The Page component currently mounts only JSpaceUI (which uses
hard-coded data from components/j-space-content.ts), replacing the QCX dashboard
entrypoint; revert this functional swap by restoring the original QCX entrypoint
and integrating JSpaceUI into it instead of replacing it: update the Page render
to include the original QCX root/component (restore whatever component you
removed) and either embed JSpaceUI within the QCX layout or feed JSpaceUI its
data via the QCX data pipeline (avoid hard-coded portfolio data), referencing
the Page component and the JSpaceUI component plus components/j-space-content.ts
so you can locate and merge the UI while keeping the QCX dashboard reachable at
"/".

In `@components/j-space-ui.tsx`:
- Around line 104-106: The JSX currently nests <button> inside <a> for
project.github and project.website; remove the inner <button> and make the
anchor itself look and behave like a button (apply the button styles/classes
instead of the nested element), keep target="_blank" and rel="noreferrer", and
add accessibility attributes such as role="button" and an appropriate aria-label
on the <a> elements to preserve keyboard and screen-reader behavior in the
component that renders project.github/project.website.
- Around line 72-80: The UI currently renders only Programming Languages, Web &
UI, and Developer Tools, so content.skills.roboticsSystems and
content.skills.dataML never appear; update the JSpace UI render (the block that
outputs the three <h3>/<p> pairs) to also render roboticsSystems and dataML —
either by adding two new sections with headings (e.g., "Robotics Systems" and
"Data & ML") and corresponding <p>{content.skills.roboticsSystems}</p> /
<p>{content.skills.dataML}</p> plus separators, or by refactoring to iterate
over content.skills keys and render all entries dynamically so no new skill
fields are dropped.
- Around line 24-31: The layout in the j-space-container uses fixed vw/vh and
absolute positioning which breaks on small viewports; update the styles in
components/j-space-ui.tsx so that .j-space-container becomes a responsive flex
container with a mobile breakpoint (e.g., `@media` max-width: 768px) that switches
to flex-direction: column, removes overflow: hidden (or sets overflow: auto) and
converts the three pane elements (the child elements currently using fixed
width/height and absolute positioning) to percent or auto heights with
min-height and full-width so they stack and can scroll; locate the styles
applied to "j-space-container" and the three pane elements (the blocks
referenced in the diff and lines 36-94) and replace fixed vw/vh/absolute
positioning with responsive rules as described.
- Around line 10-17: The component currently returns null until isLoaded becomes
true, which blanks the page if import('98-components') rejects; change the
pattern so the component renders its normal markup immediately and treats the
dynamic import as an enhancement: keep the initial render from useEffect and
setIsLoaded via import('98-components').then(() => setIsLoaded(true)).catch(err
=> { setIsLoaded(true); setImportError(err); }) or set a separate error flag so
you can show a non-blocking error UI while still rendering the main markup;
update any code around useEffect, isLoaded, and setIsLoaded to remove the early
"if (!isLoaded) return null" and instead conditionally enable features that
depend on the loaded module (e.g., only render 98-components-specific parts when
isLoaded is true).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 00ef9f85-8274-48e0-aa09-c59c52146590

📥 Commits

Reviewing files that changed from the base of the PR and between 99505ba and 1e27f9c.

⛔ Files ignored due to path filters (52)
  • bun.lock is excluded by !**/*.lock
  • public/j-space/assets/Backgroundpixels.png is excluded by !**/*.png
  • public/j-space/assets/Happy Charles Oliveira GIF by UFC.gif is excluded by !**/*.gif
  • public/j-space/assets/Jeremypixel.png is excluded by !**/*.png
  • public/j-space/assets/Rodney Mullen Skate GIF.gif is excluded by !**/*.gif
  • public/j-space/assets/all-icon.png is excluded by !**/*.png
  • public/j-space/assets/animation GIF by INSA's GIF-ITI.gif is excluded by !**/*.gif
  • public/j-space/assets/ascii-gif.gif is excluded by !**/*.gif
  • public/j-space/assets/back-icon.png is excluded by !**/*.png
  • public/j-space/assets/bear.gif is excluded by !**/*.gif
  • public/j-space/assets/binder_action.gif is excluded by !**/*.gif
  • public/j-space/assets/bjj-grappling.gif is excluded by !**/*.gif
  • public/j-space/assets/conormcgregor.gif is excluded by !**/*.gif
  • public/j-space/assets/cookie-clicker-bot.gif is excluded by !**/*.gif
  • public/j-space/assets/cruisesunset.JPG is excluded by !**/*.jpg
  • public/j-space/assets/daneilcaesar-gif.gif is excluded by !**/*.gif
  • public/j-space/assets/dark-Backgroundpixels.png is excluded by !**/*.png
  • public/j-space/assets/devpost-icon.png is excluded by !**/*.png
  • public/j-space/assets/directory_computer-0.png is excluded by !**/*.png
  • public/j-space/assets/do you even lift like a boss GIF.gif is excluded by !**/*.gif
  • public/j-space/assets/email-icon.png is excluded by !**/*.png
  • public/j-space/assets/favicon.png is excluded by !**/*.png
  • public/j-space/assets/forward-icon.png is excluded by !**/*.png
  • public/j-space/assets/github-icon.png is excluded by !**/*.png
  • public/j-space/assets/instagram-icon.png is excluded by !**/*.png
  • public/j-space/assets/j-gif-space.gif is excluded by !**/*.gif
  • public/j-space/assets/linkedin-icon.png is excluded by !**/*.png
  • public/j-space/assets/lockblock.png is excluded by !**/*.png
  • public/j-space/assets/music-player.png is excluded by !**/*.png
  • public/j-space/assets/netshow_arrow-2.png is excluded by !**/*.png
  • public/j-space/assets/paint_old.png is excluded by !**/*.png
  • public/j-space/assets/picture-painting.png is excluded by !**/*.png
  • public/j-space/assets/pixelbjj.jpg is excluded by !**/*.jpg
  • public/j-space/assets/portfolio-website-cover.png is excluded by !**/*.png
  • public/j-space/assets/portfolio-works-gif.gif is excluded by !**/*.gif
  • public/j-space/assets/qhacksbus.png is excluded by !**/*.png
  • public/j-space/assets/resume-icon.png is excluded by !**/*.png
  • public/j-space/assets/rref_calculator.PNG is excluded by !**/*.png
  • public/j-space/assets/sinatrademo.gif is excluded by !**/*.gif
  • public/j-space/assets/slot-machine.PNG is excluded by !**/*.png
  • public/j-space/assets/specifics-icon.png is excluded by !**/*.png
  • public/j-space/assets/startupgif.gif is excluded by !**/*.gif
  • public/j-space/assets/stop motion animation GIF by Ryan Seslow.gif is excluded by !**/*.gif
  • public/j-space/assets/stop_action.gif is excluded by !**/*.gif
  • public/j-space/assets/stop_dont_go_on_grey.jpg is excluded by !**/*.jpg
  • public/j-space/assets/ufc-elo-calculator-vid.mp4 is excluded by !**/*.mp4
  • public/j-space/assets/ufc-search.gif is excluded by !**/*.gif
  • public/j-space/assets/ufc_elo.png is excluded by !**/*.png
  • public/j-space/assets/user-chatbox.png is excluded by !**/*.png
  • public/j-space/assets/user-world.png is excluded by !**/*.png
  • public/j-space/assets/website-icon.png is excluded by !**/*.png
  • public/j-space/favicon.png is excluded by !**/*.png
📒 Files selected for processing (5)
  • app/layout.tsx
  • app/page.tsx
  • components/j-space-content.ts
  • components/j-space-ui.tsx
  • package.json
📜 Review details
🧰 Additional context used
🪛 Biome (2.4.6)
components/j-space-ui.tsx

[error] 105-105: Provide an explicit type prop for the button element.

(lint/a11y/useButtonType)


[error] 106-106: Provide an explicit type prop for the button element.

(lint/a11y/useButtonType)

🔇 Additional comments (1)
components/j-space-content.ts (1)

1-62: Nice separation of content from rendering.

Keeping the portfolio payload outside JSpaceUI makes the UI component much easier to evolve.

Comment on lines +7 to +9
// import Header from '@/components/header'
// import Footer from '@/components/footer'
// import { Sidebar } from '@/components/sidebar'
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Remove the commented-out layout branches.

These placeholders are dead code now and will drift from the real layout. Deleting them is cleaner than keeping commented imports/render sites around.

Also applies to: 112-116

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

In `@app/layout.tsx` around lines 7 - 9, Remove the dead commented-out layout
branches in app/layout.tsx by deleting the unused commented import lines
referencing Header, Footer, and Sidebar and any corresponding commented render
sites (including the block noted around lines 112-116); ensure no other code
relies on those commented placeholders and keep the active layout imports/JSX
only so the file contains only actual imports and render logic.

Comment on lines +7 to +8
<main>
<JSpaceUI />
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

This replaces the QCX entry point instead of integrating with it.

Page now mounts only JSpaceUI, and that component is fed by hard-coded portfolio data from components/j-space-content.ts. The existing QCX dashboard surface is no longer reachable from /, so this is a functional swap, not just a visual redesign.

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

In `@app/page.tsx` around lines 7 - 8, The Page component currently mounts only
JSpaceUI (which uses hard-coded data from components/j-space-content.ts),
replacing the QCX dashboard entrypoint; revert this functional swap by restoring
the original QCX entrypoint and integrating JSpaceUI into it instead of
replacing it: update the Page render to include the original QCX root/component
(restore whatever component you removed) and either embed JSpaceUI within the
QCX layout or feed JSpaceUI its data via the QCX data pipeline (avoid hard-coded
portfolio data), referencing the Page component and the JSpaceUI component plus
components/j-space-content.ts so you can locate and merge the UI while keeping
the QCX dashboard reachable at "/".

Comment on lines +10 to +17
useEffect(() => {
// Import 98-components only on the client side
import('98-components').then(() => {
setIsLoaded(true)
})
}, [])

if (!isLoaded) return null
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

Don't blank the page while the client-only import resolves.

isLoaded starts as false, so the initial render is null, and / stays blank forever if the 98-components import rejects. Render the markup immediately and treat the import as enhancement, or show an explicit loading/error fallback.

Possible direction
-  const [isLoaded, setIsLoaded] = useState(false)
-
   useEffect(() => {
-    // Import 98-components only on the client side
-    import('98-components').then(() => {
-      setIsLoaded(true)
-    })
+    void import('98-components').catch((error) => {
+      console.error('Failed to load 98-components', error)
+    })
   }, [])
-
-  if (!isLoaded) return null
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/j-space-ui.tsx` around lines 10 - 17, The component currently
returns null until isLoaded becomes true, which blanks the page if
import('98-components') rejects; change the pattern so the component renders its
normal markup immediately and treats the dynamic import as an enhancement: keep
the initial render from useEffect and setIsLoaded via
import('98-components').then(() => setIsLoaded(true)).catch(err => {
setIsLoaded(true); setImportError(err); }) or set a separate error flag so you
can show a non-blocking error UI while still rendering the main markup; update
any code around useEffect, isLoaded, and setIsLoaded to remove the early "if
(!isLoaded) return null" and instead conditionally enable features that depend
on the loaded module (e.g., only render 98-components-specific parts when
isLoaded is true).

Comment on lines +24 to +31
<div className="j-space-container" style={{
fontFamily: '"Jersey 10", sans-serif',
backgroundColor: '#c0c0c0',
width: '100vw',
height: '100vh',
overflow: 'hidden',
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

The window layout is not usable on small viewports.

All three panes use fixed vw/vh sizes and absolute positioning inside a container that hides overflow. On phone-sized screens the columns collapse/overlap and clipped content cannot be reached. Add a mobile breakpoint that stacks the windows and allows scrolling.

Also applies to: 36-94

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

In `@components/j-space-ui.tsx` around lines 24 - 31, The layout in the
j-space-container uses fixed vw/vh and absolute positioning which breaks on
small viewports; update the styles in components/j-space-ui.tsx so that
.j-space-container becomes a responsive flex container with a mobile breakpoint
(e.g., `@media` max-width: 768px) that switches to flex-direction: column, removes
overflow: hidden (or sets overflow: auto) and converts the three pane elements
(the child elements currently using fixed width/height and absolute positioning)
to percent or auto heights with min-height and full-width so they stack and can
scroll; locate the styles applied to "j-space-container" and the three pane
elements (the blocks referenced in the diff and lines 36-94) and replace fixed
vw/vh/absolute positioning with responsive rules as described.

Comment on lines +72 to +80
<div className="window-body">
<h3>Programming Languages</h3>
<p>{content.skills.programmingLanguages}</p>
<hr />
<h3>Web & UI</h3>
<p>{content.skills.webUI}</p>
<hr />
<h3>Developer Tools</h3>
<p>{content.skills.developerTools}</p>
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

Two content.skills fields never surface.

roboticsSystems and dataML are defined in components/j-space-content.ts, but this window only renders three sections, so part of the new content payload is silently dropped.

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

In `@components/j-space-ui.tsx` around lines 72 - 80, The UI currently renders
only Programming Languages, Web & UI, and Developer Tools, so
content.skills.roboticsSystems and content.skills.dataML never appear; update
the JSpace UI render (the block that outputs the three <h3>/<p> pairs) to also
render roboticsSystems and dataML — either by adding two new sections with
headings (e.g., "Robotics Systems" and "Data & ML") and corresponding
<p>{content.skills.roboticsSystems}</p> / <p>{content.skills.dataML}</p> plus
separators, or by refactoring to iterate over content.skills keys and render all
entries dynamically so no new skill fields are dropped.

Comment on lines +104 to +106
<div style={{ marginTop: '10px' }}>
{project.github && <a href={project.github} target="_blank" rel="noreferrer"><button>GitHub</button></a>}
{project.website && <a href={project.website} target="_blank" rel="noreferrer"><button style={{ marginLeft: '5px' }}>Website</button></a>}
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

Avoid nesting buttons inside links.

Each action is rendered as two interactive controls for one destination. That hurts keyboard/screen-reader behavior and is also why the lint rule is complaining about the inner <button>. Make the <a> look like a button instead of wrapping a button inside it.

🧰 Tools
🪛 Biome (2.4.6)

[error] 105-105: Provide an explicit type prop for the button element.

(lint/a11y/useButtonType)


[error] 106-106: Provide an explicit type prop for the button element.

(lint/a11y/useButtonType)

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

In `@components/j-space-ui.tsx` around lines 104 - 106, The JSX currently nests
<button> inside <a> for project.github and project.website; remove the inner
<button> and make the anchor itself look and behave like a button (apply the
button styles/classes instead of the nested element), keep target="_blank" and
rel="noreferrer", and add accessibility attributes such as role="button" and an
appropriate aria-label on the <a> elements to preserve keyboard and
screen-reader behavior in the component that renders
project.github/project.website.

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.

1 participant