Skip to content

Commit 49985a9

Browse files
committed
fix(desktop): resolve leftover merge conflict markers from #4 + integrate uiux iterations
The squash-merge of #4 (first-demo) accidentally pushed conflict markers in main/index.ts, preload/index.ts, App.tsx, store.ts. This commit: - Properly merges onboarding IPC + exporter IPC registration in main/index.ts - Cleans preload/index.ts (one bogus marker) - Cleans App.tsx (Onboarding gate + PreviewToolbar both retained) - Adds Wordmark component + token additions from the in-flight UIUX iterator - Bumps onboarding/Welcome polish in flight All checks green: pnpm install, pnpm -r typecheck pass. Signed-off-by: hqhq1025 <1506751656@qq.com>
1 parent 1867f38 commit 49985a9

12 files changed

Lines changed: 219 additions & 136 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,6 @@ pnpm-debug.log*
5555
# VitePress
5656
website/.vitepress/dist/
5757
website/.vitepress/cache/
58+
59+
# Playwright MCP screenshots
60+
.playwright-mcp/

apps/desktop/src/main/index.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,8 @@ import { detectProviderFromKey } from '@open-codesign/providers';
55
import { BRAND, CodesignError, GeneratePayload } from '@open-codesign/shared';
66
import { BrowserWindow, app, ipcMain, shell } from 'electron';
77
import { autoUpdater } from 'electron-updater';
8-
<<<<<<< HEAD
9-
import { getApiKeyForProvider, loadConfigOnBoot, registerOnboardingIpc } from './onboarding-ipc';
10-
||||||| parent of bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
11-
=======
128
import { registerExporterIpc } from './exporter-ipc';
13-
>>>>>>> bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
9+
import { getApiKeyForProvider, loadConfigOnBoot, registerOnboardingIpc } from './onboarding-ipc';
1410

1511
const __filename = fileURLToPath(import.meta.url);
1612
const __dirname = dirname(__filename);
@@ -86,12 +82,8 @@ function setupAutoUpdater(): void {
8682
void app.whenReady().then(async () => {
8783
await loadConfigOnBoot();
8884
registerIpcHandlers();
89-
<<<<<<< HEAD
9085
registerOnboardingIpc();
91-
||||||| parent of bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
92-
=======
9386
registerExporterIpc(() => mainWindow);
94-
>>>>>>> bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
9587
setupAutoUpdater();
9688
createWindow();
9789

apps/desktop/src/preload/index.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import type {
66
} from '@open-codesign/shared';
77
import { contextBridge, ipcRenderer } from 'electron';
88

9-
<<<<<<< HEAD
109
export interface ValidateKeyResult {
1110
ok: true;
1211
modelCount: number;
@@ -17,16 +16,13 @@ export interface ValidateKeyError {
1716
message: string;
1817
}
1918

20-
||||||| parent of bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
21-
=======
2219
export type ExportFormat = 'html' | 'pdf' | 'pptx' | 'zip';
2320
export interface ExportInvokeResponse {
2421
status: 'saved' | 'cancelled';
2522
path?: string;
2623
bytes?: number;
2724
}
2825

29-
>>>>>>> bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
3026
const api = {
3127
detectProvider: (key: string) =>
3228
ipcRenderer.invoke('codesign:detect-provider', key) as Promise<string | null>,

apps/desktop/src/renderer/src/App.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,9 @@ import { buildSrcdoc } from '@open-codesign/runtime';
22
import { BUILTIN_DEMOS } from '@open-codesign/templates';
33
import { Button } from '@open-codesign/ui';
44
import { Send, Sparkles } from 'lucide-react';
5-
<<<<<<< HEAD
65
import { useEffect, useState } from 'react';
7-
import { Onboarding } from './onboarding';
8-
||||||| parent of bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
9-
import { useState } from 'react';
10-
=======
11-
import { useState } from 'react';
126
import { PreviewToolbar } from './components/PreviewToolbar';
13-
>>>>>>> bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
7+
import { Onboarding } from './onboarding';
148
import { useCodesignStore } from './store';
159

1610
export function App() {
Lines changed: 48 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { PROVIDER_SHORTLIST, type SupportedOnboardingProvider } from '@open-codesign/shared';
2-
import { Button } from '@open-codesign/ui';
3-
import { ExternalLink, KeyRound, Rocket, Server } from 'lucide-react';
2+
import { ArrowRight, ExternalLink, KeyRound, Rocket, Server } from 'lucide-react';
43

54
interface WelcomeProps {
65
onPickKey: () => void;
@@ -10,55 +9,61 @@ interface WelcomeProps {
109

1110
export function Welcome({ onPickKey, onPickFreeTier, ollamaDetected }: WelcomeProps) {
1211
return (
13-
<div className="flex flex-col gap-6">
14-
<div>
15-
<h2 className="text-2xl font-semibold text-[var(--color-text-primary)] mb-2">
16-
Welcome to open-codesign
17-
</h2>
18-
<p className="text-sm text-[var(--color-text-secondary)]">
12+
<div className="flex flex-col gap-[var(--space-6)]">
13+
<div className="flex flex-col gap-[var(--space-2)]">
14+
<h1 className="text-[var(--text-xl)] font-semibold text-[var(--color-text-primary)] tracking-[var(--tracking-heading)] leading-[var(--leading-heading)]">
15+
Design with any model.
16+
</h1>
17+
<p className="text-[var(--text-base)] text-[var(--color-text-secondary)] leading-[var(--leading-body)]">
1918
Pick how you want to power your designs. You can change this later in Settings.
2019
</p>
2120
</div>
2221

23-
<div className="grid gap-3">
22+
<div className="flex flex-col gap-[var(--space-3)]">
2423
<PathButton
25-
icon={<Rocket className="w-5 h-5 text-[var(--color-accent)]" />}
24+
icon={<Rocket className="w-[18px] h-[18px]" />}
2625
title="Try free now"
2726
subtitle="OpenRouter free tier — paste an OpenRouter key, then pick a free model."
2827
onClick={onPickFreeTier}
2928
/>
3029
<PathButton
31-
icon={<KeyRound className="w-5 h-5 text-[var(--color-accent)]" />}
30+
icon={<KeyRound className="w-[18px] h-[18px]" />}
3231
title="Use my API key"
3332
subtitle="Anthropic, OpenAI, or OpenRouter. Auto-detected from the key prefix."
3433
onClick={onPickKey}
3534
/>
3635
{ollamaDetected ? (
3736
<PathButton
38-
icon={<Server className="w-5 h-5 text-[var(--color-text-muted)]" />}
37+
icon={<Server className="w-[18px] h-[18px]" />}
3938
title="Use local model (Ollama detected)"
4039
subtitle="Coming in v0.2 — Ollama integration is on the roadmap."
4140
disabled
4241
/>
4342
) : null}
4443
</div>
4544

46-
<div className="text-xs text-[var(--color-text-muted)] flex flex-wrap gap-x-4 gap-y-1">
47-
{(
48-
Object.values(PROVIDER_SHORTLIST) as Array<
49-
(typeof PROVIDER_SHORTLIST)[SupportedOnboardingProvider]
50-
>
51-
).map((p) => (
52-
<a
53-
key={p.provider}
54-
href={p.keyHelpUrl}
55-
target="_blank"
56-
rel="noreferrer"
57-
className="inline-flex items-center gap-1 text-[var(--color-text-muted)] hover:text-[var(--color-accent)]"
58-
>
59-
How to get a {p.label} key <ExternalLink className="w-3 h-3" />
60-
</a>
61-
))}
45+
<div className="pt-[var(--space-2)] border-t border-[var(--color-border-subtle)] flex flex-col gap-[var(--space-2)]">
46+
<span className="text-[var(--text-xs)] uppercase tracking-[var(--tracking-wide)] text-[var(--color-text-muted)] font-mono">
47+
Where to get a key
48+
</span>
49+
<div className="flex flex-wrap gap-x-[var(--space-4)] gap-y-[var(--space-1)]">
50+
{(
51+
Object.values(PROVIDER_SHORTLIST) as Array<
52+
(typeof PROVIDER_SHORTLIST)[SupportedOnboardingProvider]
53+
>
54+
).map((p) => (
55+
<a
56+
key={p.provider}
57+
href={p.keyHelpUrl}
58+
target="_blank"
59+
rel="noreferrer"
60+
className="inline-flex items-center gap-[4px] text-[var(--text-xs)] text-[var(--color-text-secondary)] hover:text-[var(--color-accent)] transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out)]"
61+
>
62+
{p.label}
63+
<ExternalLink className="w-[11px] h-[11px]" />
64+
</a>
65+
))}
66+
</div>
6267
</div>
6368
</div>
6469
);
@@ -74,18 +79,24 @@ interface PathButtonProps {
7479

7580
function PathButton({ icon, title, subtitle, onClick, disabled }: PathButtonProps) {
7681
return (
77-
<Button
78-
variant="secondary"
79-
size="lg"
82+
<button
83+
type="button"
8084
onClick={onClick}
8185
disabled={disabled}
82-
className="!h-auto !justify-start text-left py-4"
86+
className="group relative flex items-start gap-[var(--space-4)] w-full text-left p-[var(--space-4)] rounded-[var(--radius-lg)] bg-[var(--color-surface)] border border-[var(--color-border)] shadow-[var(--shadow-soft)] transition-[transform,box-shadow,border-color,background-color] duration-[var(--duration-base)] ease-[var(--ease-out)] hover:-translate-y-[1px] hover:border-[var(--color-border-strong)] hover:shadow-[var(--shadow-card)] disabled:opacity-50 disabled:pointer-events-none"
8387
>
84-
<span className="shrink-0">{icon}</span>
85-
<span className="flex flex-col items-start gap-0.5">
86-
<span className="text-sm font-medium text-[var(--color-text-primary)]">{title}</span>
87-
<span className="text-xs text-[var(--color-text-muted)] font-normal">{subtitle}</span>
88+
<span className="shrink-0 mt-[2px] inline-flex items-center justify-center w-[34px] h-[34px] rounded-[var(--radius-md)] bg-[var(--color-accent-soft)] text-[var(--color-accent)]">
89+
{icon}
8890
</span>
89-
</Button>
91+
<span className="flex flex-col gap-[2px] flex-1 min-w-0">
92+
<span className="text-[var(--text-base)] font-semibold text-[var(--color-text-primary)] tracking-[var(--tracking-tight)]">
93+
{title}
94+
</span>
95+
<span className="text-[var(--text-xs)] text-[var(--color-text-secondary)] leading-[var(--leading-ui)]">
96+
{subtitle}
97+
</span>
98+
</span>
99+
<ArrowRight className="w-[14px] h-[14px] mt-[10px] shrink-0 text-[var(--color-text-muted)] opacity-0 -translate-x-[4px] transition-[opacity,transform] duration-[var(--duration-base)] ease-[var(--ease-out)] group-hover:opacity-100 group-hover:translate-x-0 group-hover:text-[var(--color-accent)]" />
100+
</button>
90101
);
91102
}

apps/desktop/src/renderer/src/onboarding/index.tsx

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { PROVIDER_SHORTLIST, type SupportedOnboardingProvider } from '@open-codesign/shared';
2-
import { Sparkles } from 'lucide-react';
2+
import { Wordmark } from '@open-codesign/ui';
33
import { useState } from 'react';
44
import { useCodesignStore } from '../store';
55
import { ChooseModel } from './ChooseModel';
@@ -45,15 +45,22 @@ export function Onboarding() {
4545
}
4646
}
4747

48+
const idx = stepIndex(step);
49+
4850
return (
49-
<div className="h-full flex items-center justify-center bg-[var(--color-background)] px-6 py-8">
50-
<div className="w-full max-w-md bg-[var(--color-surface)] border border-[var(--color-border)] rounded-[var(--radius-2xl)] shadow-[var(--shadow-card)] p-8 flex flex-col gap-6">
51-
<header className="flex items-center gap-2">
52-
<Sparkles className="w-5 h-5 text-[var(--color-accent)]" />
53-
<span className="font-semibold text-[var(--color-text-primary)]">open-codesign</span>
54-
<span className="ml-auto text-xs text-[var(--color-text-muted)]">
55-
Step {stepIndex(step)} of 3
56-
</span>
51+
<div className="h-full flex items-center justify-center bg-[var(--color-background)] px-[var(--space-6)] py-[var(--space-8)] relative overflow-hidden">
52+
<div
53+
aria-hidden="true"
54+
className="pointer-events-none absolute inset-0"
55+
style={{
56+
background:
57+
'radial-gradient(ellipse 80% 50% at 50% 0%, var(--color-accent-soft), transparent 70%)',
58+
}}
59+
/>
60+
<div className="relative w-full max-w-[480px] bg-[var(--color-surface)] border border-[var(--color-border)] rounded-[var(--radius-2xl)] shadow-[var(--shadow-card)] p-[var(--space-8)] flex flex-col gap-[var(--space-6)]">
61+
<header className="flex items-center justify-between">
62+
<Wordmark badge="pre-alpha" />
63+
<Stepper current={idx} total={3} />
5764
</header>
5865

5966
{step === 'welcome' ? (
@@ -83,6 +90,29 @@ export function Onboarding() {
8390
);
8491
}
8592

93+
function Stepper({ current, total }: { current: number; total: number }) {
94+
return (
95+
<div className="flex items-center gap-[var(--space-2)]">
96+
<span className="text-[var(--text-xs)] font-mono text-[var(--color-text-muted)] tracking-[0.04em]">
97+
{current.toString().padStart(2, '0')} / {total.toString().padStart(2, '0')}
98+
</span>
99+
<span className="flex items-center gap-[3px]" aria-hidden="true">
100+
{Array.from({ length: total }).map((_, i) => (
101+
<span
102+
// biome-ignore lint/suspicious/noArrayIndexKey: stepper dots are positional
103+
key={i}
104+
className={`h-[3px] rounded-[var(--radius-full)] transition-[width,background-color] duration-[var(--duration-base)] ease-[var(--ease-out)] ${
105+
i < current
106+
? 'w-[14px] bg-[var(--color-accent)]'
107+
: 'w-[6px] bg-[var(--color-border-strong)]'
108+
}`}
109+
/>
110+
))}
111+
</span>
112+
</div>
113+
);
114+
}
115+
86116
function stepIndex(step: Step): number {
87117
if (step === 'welcome') return 1;
88118
if (step === 'paste') return 2;

apps/desktop/src/renderer/src/store.ts

Lines changed: 2 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,11 @@ interface CodesignState {
2626
previewHtml: string | null;
2727
isGenerating: boolean;
2828
errorMessage: string | null;
29-
<<<<<<< HEAD
3029
config: OnboardingState | null;
3130
configLoaded: boolean;
31+
toastMessage: string | null;
3232
loadConfig: () => Promise<void>;
3333
completeOnboarding: (next: OnboardingState) => void;
34-
||||||| parent of bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
35-
=======
36-
toastMessage: string | null;
37-
>>>>>>> bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
3834
sendPrompt: (prompt: string) => Promise<void>;
3935
exportActive: (format: ExportFormat) => Promise<void>;
4036
dismissToast: () => void;
@@ -49,9 +45,9 @@ export const useCodesignStore = create<CodesignState>((set, get) => ({
4945
previewHtml: null,
5046
isGenerating: false,
5147
errorMessage: null,
52-
<<<<<<< HEAD
5348
config: null,
5449
configLoaded: false,
50+
toastMessage: null,
5551

5652
async loadConfig() {
5753
if (!window.codesign) {
@@ -68,10 +64,6 @@ export const useCodesignStore = create<CodesignState>((set, get) => ({
6864
completeOnboarding(next: OnboardingState) {
6965
set({ config: next });
7066
},
71-
||||||| parent of bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
72-
=======
73-
toastMessage: null,
74-
>>>>>>> bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
7567

7668
async sendPrompt(prompt: string) {
7769
if (get().isGenerating) return;
@@ -92,44 +84,6 @@ export const useCodesignStore = create<CodesignState>((set, get) => ({
9284
errorMessage: null,
9385
}));
9486

95-
<<<<<<< HEAD
96-
||||||| parent of bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
97-
// Tier 1 wiring: hardcoded provider/model and key-from-env until the
98-
// onboarding flow lands. The real flow will read from the keychain.
99-
const apiKey = '';
100-
if (!apiKey) {
101-
set((s) => ({
102-
messages: [
103-
...s.messages,
104-
{
105-
role: 'assistant',
106-
content:
107-
'No API key configured yet. Onboarding flow coming in v0.1 — see docs/research/06-api-onboarding-ux.md.',
108-
},
109-
],
110-
isGenerating: false,
111-
}));
112-
return;
113-
}
114-
115-
=======
116-
const apiKey = DEV_API_KEY;
117-
if (!apiKey) {
118-
set((s) => ({
119-
messages: [
120-
...s.messages,
121-
{
122-
role: 'assistant',
123-
content:
124-
'No API key configured yet. Set VITE_OPEN_CODESIGN_DEV_KEY for dev, or wait for the onboarding flow (wt/onboarding) to land.',
125-
},
126-
],
127-
isGenerating: false,
128-
}));
129-
return;
130-
}
131-
132-
>>>>>>> bca116c (feat(core,exporters,desktop): end-to-end first demo + HTML export)
13387
try {
13488
const result = await window.codesign.generate({
13589
prompt,

0 commit comments

Comments
 (0)