Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,36 @@ All while maintaining **100% open-source transparency** and enabling self-hostin

## Templates

### Resume Templates

<table>
<tr>
<td align="center">
<img src="apps/studio/public/templates/precision-ats.png" alt="Precision ATS" width="300" />
<img src="apps/studio/public/templates/resume/precision-ats.png" alt="Precision ATS" width="300" />
<br /><sub><b>Precision ATS</b></sub>
</td>
<td align="center">
<img src="apps/studio/public/templates/executive-clarity.png" alt="Executive Clarity" width="300" />
<img src="apps/studio/public/templates/resume/executive-clarity.png" alt="Executive Clarity" width="300" />
<br /><sub><b>Executive Clarity</b></sub>
</td>
</tr>
</table>

### Cover Letter Templates

<table>
<tr>
<td align="center">
<img src="apps/studio/public/templates/cover-letter/professional.png" alt="Professional" width="300" />
<br /><sub><b>Professional</b></sub>
</td>
<td align="center">
<img src="apps/studio/public/templates/cover-letter/veriworkly-special.png" alt="Veriworkly Special" width="300" />
<br /><sub><b>Veriworkly Special</b></sub>
</td>
</tr>
</table>

## Architecture and Technology Stack

VeriWorkly utilizes a modern, type-safe monorepo architecture to ensure service isolation and scalability.
Expand Down
28 changes: 22 additions & 6 deletions apps/studio/components/dashboard/StudioShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ import {
} from "@/components/dashboard/StudioNavigation";
import { ThemeToggle } from "@/components/dashboard/ThemeToggle";
import { AccountMenu } from "@/components/dashboard/AccountMenu";
import { NewDocumentButton } from "@/components/dashboard/NewDocumentModal";
import { NewDocumentButton, NewDocumentModal } from "@/components/dashboard/NewDocumentModal";
import { WorkspaceSearchModal } from "@/components/dashboard/WorkspaceSearchModal";

import { createResume } from "@/features/resume/services/resume-service";
import { signOutCurrentUser } from "@/features/auth/services/current-user";
import { createDocument } from "@/features/documents/services/document-workspace-service";
import type { DocumentType } from "@/features/documents/core/document-types";

import { cn } from "@/lib/utils";

Expand All @@ -43,13 +45,21 @@ const StudioShell = ({ children, mainClassName }: StudioShellProps) => {
const [collapsed, setCollapsed] = useState(false);
const [searchOpen, setSearchOpen] = useState(false);
const [mobileNavOpen, setMobileNavOpen] = useState(false);
const [newDocumentOpen, setNewDocumentOpen] = useState(false);

const email = user?.email || "No account connected";
const displayName = user?.name || user?.email?.split("@")[0] || "Local builder";

const createNewResume = () => {
const resume = createResume();
router.push(`/editor/resume/${resume.id}`);
const createNewDocument = (type: DocumentType) => {
if (type === "RESUME") {
const resume = createResume();
router.push(`/editor/resume/${resume.id}`);

return;
}

const document = createDocument(type);
router.push(`/editor/${type.toLowerCase()}/${document.id}`);
};

const handleLogout = async () => {
Expand Down Expand Up @@ -126,7 +136,7 @@ const StudioShell = ({ children, mainClassName }: StudioShellProps) => {
</div>

<div className="px-2">
<NewDocumentButton collapsed={collapsed} onClick={createNewResume} />
<NewDocumentButton collapsed={collapsed} onClick={() => setNewDocumentOpen(true)} />
</div>

{!collapsed ? (
Expand Down Expand Up @@ -187,7 +197,7 @@ const StudioShell = ({ children, mainClassName }: StudioShellProps) => {
</Link>

<div className="flex items-center gap-2">
<NewDocumentButton compact onClick={createNewResume} />
<NewDocumentButton compact onClick={() => setNewDocumentOpen(true)} />

<button
type="button"
Expand Down Expand Up @@ -231,6 +241,12 @@ const StudioShell = ({ children, mainClassName }: StudioShellProps) => {
onOpenDocument={(id) => router.push(`/editor/resume/${id}`)}
/>

<NewDocumentModal
open={newDocumentOpen}
onCreate={createNewDocument}
onClose={() => setNewDocumentOpen(false)}
/>

<div
className={cn(
"relative min-w-0 flex-1 bg-[radial-gradient(circle_at_top_left,color-mix(in_oklab,var(--accent)_13%,transparent),transparent_28rem),linear-gradient(180deg,color-mix(in_oklab,var(--card)_62%,var(--background)),var(--background)_18rem)] p-4 sm:p-6 xl:p-8",
Expand Down
68 changes: 58 additions & 10 deletions apps/studio/features/cover-letter/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,81 @@ import type { BaseDocument } from "@/features/documents/core/types";

import type { CoverLetterContent } from "./types";

export const COVER_LETTER_TEMPLATE_ID = "cover-letter-classic";
export const COVER_LETTER_TEMPLATE_ID = "professional";

export function createDefaultCoverLetter(id: string): BaseDocument<CoverLetterContent> {
const now = new Date().toISOString();
return {
id,
type: "COVER_LETTER",
title: "Cover Letter",
title: "Product Engineer - Veriworkly",
templateId: COVER_LETTER_TEMPLATE_ID,

updatedAt: now,

sync: {
enabled: false,
status: "local-only",
cloudDocumentId: null,
lastSyncedAt: null,
revision: 1,
},

content: {
recipientName: "",
recipientTitle: "",
companyName: "",
subject: "",
greeting: "Dear Hiring Manager,",
opening: "",
body: "",
senderName: "Veriworkly User",
senderTitle: "Product Engineer",
senderEmail: "user@veriworkly.com",
senderPhone: "+1 (555) 010-2026",
senderLocation: "Remote",
senderWebsite: "veriworkly.com",
senderLinks: "",

links: {
displayMode: "icon-username",
items: [],
},

date: new Intl.DateTimeFormat("en", {
year: "numeric",
month: "long",
day: "numeric",
}).format(new Date()),

recipientName: "Veriworkly Hiring Team",
recipientTitle: "Product and Engineering",

companyName: "Veriworkly",
companyLocation: "Remote",

jobTitle: "Product Engineer",
subject: "Application for Product Engineer at Veriworkly",

greeting: "Dear Veriworkly Hiring Team,",

opening:
"I am excited to apply for the Product Engineer role at Veriworkly. The product mission is close to the work I care about: helping people present credible professional documents, move faster through career workflows, and keep their materials consistent across resume, cover letter, and document experiences.",

body: "I would bring a practical product engineering mindset to Veriworkly. I enjoy building polished document editors, export flows, cloud sync, sharing, and preview experiences that feel dependable for real users. I care about details like autosave behavior, hydration-safe rendering, reusable document actions, and templates that help users start with strong defaults instead of a blank page.\n\nVeriworkly stands out because it combines user-facing craft with systems that need to be trustworthy: local drafts, public links, document exports, and collaboration between dashboard and editor surfaces. I would be excited to help make those workflows sharper, faster, and easier to maintain.",

highlights:
"- Built React and TypeScript document workflows with live preview, export, and autosave behavior\n- Improved shared UI actions so resumes, cover letters, and other documents behave consistently\n- Debugged hydration, routing, and local-storage edge cases in Next.js applications",

closing: "Sincerely,",
signature: "",
signature: "Veriworkly User",

postscript:
"I would welcome the chance to help Veriworkly make professional document creation feel faster, clearer, and more reliable.",

appearance: {
fontFamily: "geist",
pageMargin: 40,
paragraphSpacing: 10,
lineHeight: 1.5,
accentColor: "#2563eb",
sidebarColor: "#f8fafc",
pageColor: "#ffffff",
textColor: "#18181b",
},
},
};
}
Loading
Loading