Skip to content

Feat/personal site#13

Merged
ghostleek merged 28 commits intomainfrom
feat/personal-site
Feb 12, 2026
Merged

Feat/personal site#13
ghostleek merged 28 commits intomainfrom
feat/personal-site

Conversation

@ghostleek
Copy link
Contributor

This pull request introduces a comprehensive UI design system for the String app, refines the app's component architecture, and improves the development workflow and API error handling. Key highlights include the addition of a detailed design system documentation, new reusable UI components, enhanced mobile interactions, and a dedicated dev API server for local development.

Design System & UI Architecture

  • Added STYLING.md to document the new String Design System, specifying brand color palette, component patterns, layout standards, and theme support.
  • Updated claude.md to reflect Phase 4 completion, listing the design system, component library (Button, Card, AppCard, Header), and component architecture for better dev/prod consistency. [1] [2] [3] [4] [5] [6]

Component & Interaction Enhancements

  • Refactored src/App.tsx to use new reusable UI components and replaced long-press interactions with swipe gestures for mobile (using useSwipe instead of useLongPress), improving mobile UX for pin/unpin actions. [1] [2] [3] [4] [5] [6]

Development Workflow Improvements

  • Added a new dev API server (server/dev-server.js) using Express for local development, with endpoints for app submissions and user-specific queries.
  • Updated package.json scripts to support concurrent running of client and API servers for a smoother dev experience, and added concurrently as a dependency. [1] [2]

API & Error Handling

  • Improved error responses in api/submissions.ts to include error details, and added logging for better debugging. [1] [2]

Branding & Meta Updates

  • Updated index.html to use the new brand color (#33373B) for theme and tile colors, and added a comprehensive set of favicons and Apple touch icons.

@ghostleek ghostleek self-assigned this Feb 12, 2026
@ghostleek ghostleek added the enhancement New feature or request label Feb 12, 2026
@vercel
Copy link

vercel bot commented Feb 12, 2026

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

Project Deployment Actions Updated (UTC)
string-v2 Ready Ready Preview, Comment Feb 12, 2026 3:44pm

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a String UI design system + reusable component library, refactors the main app/dashboard/profile UIs around those components (including new swipe interactions on mobile), and introduces a local Express-based dev API server with Vite proxying to improve local development.

Changes:

  • Introduces a documented design system (STYLING.md) and a set of reusable UI components (Button/Card/Modal/etc.), then refactors profile + dashboard screens to use them.
  • Replaces long-press interactions with swipe gestures for pin/unpin and adds a “Submit App” modal flow from both homepage and dashboard.
  • Adds a local dev API server (server/dev-server.js) and updates tooling/config (Vite proxy, npm scripts, Vercel rewrites/headers, favicon/touch icons).

Reviewed changes

Copilot reviewed 33 out of 72 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
vite.config.ts Proxies /api to the local dev API server for local development.
vercel.json Adds caching headers for icons and refines SPA rewrites to avoid rewriting static assets.
src/lib/auth-client.ts Simplifies user-save API call to always use /api/users and adjusts logging.
src/hooks/useSwipe.ts New swipe-gesture hook for mobile interactions.
src/db/schema.ts Updates user ID types to text, removes some FKs, and adds submission analytics counters.
src/components/ui/PinButton.tsx New reusable pin/unpin icon button component.
src/components/ui/Modal.tsx New modal component used for “Submit App” flows.
src/components/ui/LaunchButton.tsx New reusable “open in new tab” icon link component.
src/components/ui/IconButton.tsx New generic icon button component.
src/components/ui/Header.tsx New header component for branded top navigation.
src/components/ui/DashboardHeader.tsx New dashboard-specific header with tabs, theme toggle, and user menu.
src/components/ui/Card.tsx New card wrapper component for consistent layout/styling.
src/components/ui/Button.tsx New shared button component implementing design-system variants/sizes.
src/components/ui/AppCard.tsx New app display card used in app lists/grids.
src/components/profile/ProfileHeader.tsx New profile header block for personal profile pages.
src/components/profile/ProfileFooter.tsx New branded footer for profile pages.
src/components/profile/AppsList.tsx New apps list/grid with contribution-first sorting.
src/components/dashboard/MySubmissions.tsx New dashboard submissions view (desktop table + mobile cards).
src/components/UserDashboard.tsx Refactors dashboard to use new header, modal submission flow, and MySubmissions component.
src/components/Router.tsx Routes profile pages to a dev mock in local development.
src/components/ProfileModal.tsx Adds profile-as-modal component (currently unused).
src/components/PersonalProfile.tsx Refactors personal profile view to use new profile components.
src/components/Footer.tsx Renames footer links (“Privacy Policy”→“Privacy”, “Terms & Conditions”→“Terms”).
src/components/DevProfileMock.tsx Adds a local-development mock profile page for testing without backend dependencies.
src/components/AuthButton.tsx Adds authenticated dropdown menu actions (“My Launcher”, dashboard, sign out).
src/components/AppSubmissionForm.tsx Adds app autocomplete, improved messaging, and onSuccess callback support for modal usage.
src/App.tsx Integrates new UI components, swipe interactions, and “Submit App” modal from the homepage.
server/dev-server.js Adds local Express dev API server for /api/users and /api/submissions.
public/apple-touch-icon-iphone-retina-120x120.png Adds Apple touch icon asset.
public/apple-touch-icon-iphone-60x60.png Adds Apple touch icon asset.
public/apple-touch-icon-ipad-retina-152x152.png Adds Apple touch icon asset.
public/apple-touch-icon-ipad-76x76.png Adds Apple touch icon asset.
package.json Adds concurrently and scripts to run client+dev API together.
package-lock.json Locks new dependencies introduced by concurrently.
index.html Updates theme color and adds favicon/touch icon/meta tags.
claude.md Updates project status/architecture documentation.
api/submissions.ts Enhances submissions API with user existence checks and richer error responses.
STYLING.md New design system documentation (colors, patterns, layout standards, theming).
.gitignore Ignores .env*.local files.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +109 to +116
app.get('/api/submissions', async (req, res) => {
try {
const userId = req.query.userId;

if (!userId) {
return res.status(400).json({ error: 'Missing userId parameter' });
}

Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

The /api/submissions GET handler requires userId in the query string, but current frontend calls don't send it. Either relax this in dev (e.g., infer from auth in headers / accept missing param) or update frontend to always pass userId so local dev matches production behavior.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

Comment on lines 140 to +146
} catch (error) {
console.error('Database error:', error);
return new Response(
JSON.stringify({ error: 'Internal server error' }),
JSON.stringify({
error: 'Internal server error',
details: error instanceof Error ? error.message : 'Unknown error'
}),
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

The 500 response includes details derived from error.message. In production this can leak internal/database details to clients. Consider logging the detailed error server-side only and returning a generic error response (or gate details behind a development flag).

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

Comment on lines +6 to +11
<a href="/" className="text-string-mint hover:text-string-mint-light font-medium transition-colors">
<img
src="/Brand Guidelines/4. Svg Separate Files/primary_dark.svg"
alt="String"
className="h-4 inline"
/>
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

This image path points to /Brand Guidelines/..., but that folder is not part of the Vite public/ assets and won't be available in the built app (404 in production). Copy the required SVG into public/ (e.g. public/logo-dark.svg) and reference it from there, or import it via the bundler.

Copilot uses AI. Check for mistakes.
Comment on lines 24 to 26

console.log('AuthButton render - user:', user, 'isAuthenticated:', isAuthenticated, 'isLoading:', isLoading);

Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

There is a console.log in the render path. This will spam production logs and can leak user info (email) to the console. Consider removing it or gating behind a development-only check.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

Comment on lines +1 to +2
import { useState, useEffect } from 'react';
import { PersonalProfile } from './PersonalProfile';
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

PersonalProfile is imported but never used in this file. With noUnusedLocals: true in tsconfig.json, this will fail TypeScript builds. Remove the unused import (or use it instead of duplicating profile rendering here).

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

Comment on lines +28 to +35
const loadSubmissions = async () => {
try {
setLoading(true);
const response = await fetch('/api/submissions');
if (response.ok) {
const data = await response.json();
setSubmissions(data.submissions);
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

GET /api/submissions requires a userId query parameter (see both api/submissions.ts and server/dev-server.js), but this fetch calls /api/submissions without it. This will always 400 and the submissions list will never load. Consider pulling userId from useAuth() here (or pass it in as a prop) and request /api/submissions?userId=....

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +79
// Ensure user exists in database before creating submission
const existingUser = await db
.select()
.from(users)
.where(eq(users.id, submittedByUserId))
.limit(1);

if (existingUser.length === 0) {
// Create user if doesn't exist
await db.insert(users).values({
id: submittedByUserId,
email: submittedByEmail,
name: null,
slug: null,
});
}
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

Creating a placeholder user with slug: null can permanently break profile routing: api/users.ts only generates a slug when the user does not already exist, and does not backfill a missing slug on updates. If a user is inserted here first, they may never get a slug. Suggest reusing the same slug-generation/upsert logic as api/users.ts (or update existing users where slug IS NULL).

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

Comment on lines +46 to +67
return (
<div className="fixed inset-0 z-50 overflow-y-auto">
{/* Backdrop */}
<div
className="fixed inset-0 bg-black bg-opacity-50 transition-opacity"
onClick={onClose}
/>

{/* Modal */}
<div className="flex min-h-full items-center justify-center p-4">
<div className={`relative w-full ${sizeClasses[size]} bg-white rounded-xl shadow-xl`}>
{/* Header */}
<div className="flex items-center justify-between p-6 border-b border-gray-200">
<h3 className="text-lg font-semibold text-string-dark">{title}</h3>
<button
onClick={onClose}
className="p-1 rounded-lg text-gray-400 hover:text-gray-600 hover:bg-gray-100 transition-colors"
>
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

The modal is missing key accessibility semantics and focus management (e.g., role="dialog", aria-modal="true", aria-labelledby, and trapping focus / returning focus to the trigger). Without these, keyboard and screen-reader users can have a broken experience. Consider adding the ARIA attributes at minimum, and ideally a focus trap (or use an accessible dialog primitive).

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

Comment on lines +516 to +520
'bg-white border border-gray-100 hover:border-string-mint hover:shadow-sm',
'bg-[#2a2d30] border border-[#3a3f44] hover:border-string-mint'
)} ${swipeProps.isSwipeMenuOpen ? 'transform -translate-x-20' : ''}`}
{...swipeProps}
>
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

Same issue here: spreading the full useSwipe() return object onto a <div> passes non-standard props to the DOM. Only spread the touch/click handlers (or a bind object) and keep state values separate.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

Comment on lines +15 to +35
app.use(cors());
app.use(express.json());

const connectionString = process.env.DATABASE_URL;
if (!connectionString) {
console.error('DATABASE_URL environment variable is not set');
process.exit(1);
}

const sqlClient = neon(connectionString);
const db = drizzle(sqlClient);

// POST /api/users
app.post('/api/users', async (req, res) => {
try {
const { id, email, name, image, provider } = req.body;
if (!id || !email) {
return res.status(400).json({ error: 'id and email are required' });
}

const slug = generateSlugFromEmail(email);
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

This dev server doesn't implement GET /api/apps, but the client fetches /api/apps (App.tsx and AppSubmissionForm.tsx). With the Vite /api proxy pointing to this server, local dev will 404 for the app directory and autocomplete. Add a GET /api/apps route here (or adjust the proxy to exclude /api/apps).

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

Copy link
Contributor

Copilot AI commented Feb 12, 2026

@ghostleek I've opened a new pull request, #15, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI commented Feb 12, 2026

@ghostleek I've opened a new pull request, #16, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI commented Feb 12, 2026

@ghostleek I've opened a new pull request, #17, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI commented Feb 12, 2026

@ghostleek I've opened a new pull request, #18, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI commented Feb 12, 2026

@ghostleek I've opened a new pull request, #19, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI commented Feb 12, 2026

@ghostleek I've opened a new pull request, #20, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI commented Feb 12, 2026

@ghostleek I've opened a new pull request, #21, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI commented Feb 12, 2026

@ghostleek I've opened a new pull request, #22, to work on those changes. Once the pull request is ready, I'll request review from you.

@ghostleek ghostleek merged commit 382240b into main Feb 12, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants