Skip to content
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

Implement Custom CSS Feature #2146

Merged
merged 2 commits into from
Jan 13, 2025
Merged

Implement Custom CSS Feature #2146

merged 2 commits into from
Jan 13, 2025

Conversation

AmruthPillai
Copy link
Owner

@AmruthPillai AmruthPillai commented Jan 12, 2025

Custom CSS is back!

Screenshot 2025-01-13 at 12 27 50 AM

Summary by CodeRabbit

Release Notes v4.3.5

  • New Features

    • Added a custom CSS section in the resume builder.
    • Introduced ability to apply custom CSS styles to resumes.
    • Enhanced syntax highlighting for code snippets.
  • Improvements

    • Updated default CSS styling to apply universally across elements.
    • Added support for additional font variants.
  • Dependencies

    • Added Prism.js for syntax highlighting.
    • Integrated react-simple-code-editor.
    • Updated to include new development dependencies.

Copy link

coderabbitai bot commented Jan 12, 2025

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

This pull request introduces a comprehensive feature for custom CSS in the resume builder application. The changes span multiple files and components, enabling users to apply custom CSS styles dynamically. Key modifications include adding a new CSS section in the right sidebar, implementing a code editor for CSS input, updating metadata schemas, and ensuring custom CSS can be applied during PDF generation and in the artboard view.

Changes

File Change Summary
apps/artboard/src/pages/artboard.tsx Added conditional rendering of <style> element based on metadata.css.visible
apps/client/public/styles/prism-*.css Added syntax highlighting styles for code blocks and inline code
apps/client/public/templates/json/*.json Updated CSS metadata to use universal selector * instead of .section
apps/client/src/pages/builder/sidebars/right/index.tsx Added CssSection and corresponding SectionIcon
apps/client/src/pages/builder/sidebars/right/sections/css.tsx Created new CssSection component for managing custom CSS
apps/server/src/printer/printer.service.ts Added logic to apply custom CSS during PDF generation
libs/schema/src/metadata/index.ts Updated default CSS and typography metadata
package.json Updated version and added dependencies for code editing

Assessment against linked issues

Objective Addressed Explanation
Custom CSS Feature [#1769, #1600]
Dynamic CSS Application
CSS Visibility Toggle
Typography Flexibility [#1084] Added font variant options

Possibly related PRs

Suggested reviewers

  • DemaPy

Poem

🐰 A Rabbit's Ode to Custom CSS 🎨

With brackets and braces, a style so divine,
Custom CSS now dances, line by line!
From .section to *, our selectors leap,
Designing resumes with a creative sweep!

Hop, hop, hooray for flexible design! 🌈


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 43c5a33 and eab996f.

📒 Files selected for processing (2)
  • apps/client/public/styles/prism-dark.css (1 hunks)
  • apps/client/src/pages/builder/sidebars/right/sections/css.tsx (1 hunks)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

nx-cloud bot commented Jan 12, 2025

View your CI Pipeline Execution ↗ for commit eab996f.

Command Status Duration Result
nx run-many -t build ✅ Succeeded 2s View ↗
nx run-many -t lint ✅ Succeeded 1m 13s View ↗

☁️ Nx Cloud last updated this comment at 2025-01-13 00:09:11 UTC

Copy link

@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: 5

🧹 Nitpick comments (9)
apps/client/src/pages/builder/sidebars/right/sections/css.tsx (1)

22-25: Consider bundling Prism themes.

Loading Prism themes from external files could cause flash of unstyled content. Consider bundling the themes with the application.

- {isDarkMode && <link rel="stylesheet" href="/styles/prism-dark.css" />}
- {!isDarkMode && <link rel="stylesheet" href="/styles/prism-light.css" />}
+ import "prismjs/themes/prism-dark.css";
+ import "prismjs/themes/prism.css";
apps/client/src/pages/builder/sidebars/right/index.tsx (1)

91-97: Consider adding ARIA label for better accessibility.

The section icon for Custom CSS could benefit from an ARIA label to improve screen reader support.

 <SectionIcon
   id="css"
   name={t`Custom CSS`}
+  aria-label={t`Navigate to Custom CSS section`}
   onClick={() => {
     scrollIntoView("#css");
   }}
 />
libs/schema/src/sample.ts (1)

311-311: Consider using a more specific CSS selector.

Using the universal selector * might affect elements that shouldn't have outlines (e.g., icons, images). Consider using a more targeted selector or adding exclusions.

-  value: "* {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}",
+  value: ".resume-section {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}\n.resume-section * {\n\toutline: inherit;\n}",
apps/client/public/templates/json/ditto.json (1)

318-318: Consider performance implications of universal selector.

Using the universal selector * to apply outlines to every element could impact rendering performance, especially for complex documents. Consider limiting the scope to specific container elements or using a more targeted selector.

-      "value": "* {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}",
+      "value": ".resume-section {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}",
apps/client/public/styles/prism-dark.css (1)

62-65: Consider adding CSS custom properties for token colors.

Using CSS variables for token colors would make it easier to maintain and switch between themes.

+:root {
+  --prism-boolean: #00e0e0;
+  /* Add other token colors as variables */
+}
 .token.boolean,
 .token.number {
-  color: #00e0e0;
+  color: var(--prism-boolean);
 }
apps/client/public/templates/json/rhyhorn.json (1)

291-291: Consider performance implications of universal selector

The change from .section to * selector will affect all elements in the document. While this might be useful for debugging, it could impact rendering performance when enabled.

Consider using a more specific selector or adding a common class to elements that need the outline:

-      "value": "* {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}",
+      "value": "[data-outline] {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}",
apps/client/public/templates/json/onyx.json (1)

290-290: Consider performance and visual implications of universal selector

While the universal selector * provides comprehensive outline visualization for debugging, it might impact performance and create visual clutter. Consider:

  1. Using a more specific selector for better performance
  2. Adding a comment explaining the debugging purpose
-      "value": "* {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}",
+      "value": "/* Debug mode: Visualize element boundaries */\n.resume-section, .resume-section * {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}",
apps/client/public/templates/json/azurill.json (1)

292-292: Add a comment explaining the debugging purpose of this CSS.

Consider adding a comment in the metadata to clarify that this outline styling is intended for development/debugging purposes. This would help other developers understand why the universal selector is being used.

 "css": {
       "value": "* {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}",
-      "visible": false
+      "visible": false,
+      "description": "Debug outline to visualize element boundaries during development"
     },
apps/client/public/templates/json/gengar.json (1)

292-292: Consider centralizing shared template configurations.

Since this debugging CSS is identical across all templates, consider extracting it into a shared configuration file. This would make future updates easier and ensure consistency.

You could:

  1. Create a shared metadata configuration file
  2. Import shared settings into individual templates
  3. Allow templates to override specific values when needed

This would reduce duplication and make the codebase more maintainable.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7fb0226 and 43c5a33.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (22)
  • apps/artboard/src/pages/artboard.tsx (1 hunks)
  • apps/client/public/styles/prism-dark.css (1 hunks)
  • apps/client/public/styles/prism-light.css (1 hunks)
  • apps/client/public/templates/json/azurill.json (1 hunks)
  • apps/client/public/templates/json/bronzor.json (1 hunks)
  • apps/client/public/templates/json/chikorita.json (1 hunks)
  • apps/client/public/templates/json/ditto.json (1 hunks)
  • apps/client/public/templates/json/gengar.json (1 hunks)
  • apps/client/public/templates/json/glalie.json (1 hunks)
  • apps/client/public/templates/json/kakuna.json (1 hunks)
  • apps/client/public/templates/json/leafish.json (1 hunks)
  • apps/client/public/templates/json/nosepass.json (1 hunks)
  • apps/client/public/templates/json/onyx.json (1 hunks)
  • apps/client/public/templates/json/pikachu.json (1 hunks)
  • apps/client/public/templates/json/rhyhorn.json (1 hunks)
  • apps/client/src/pages/builder/sidebars/right/index.tsx (3 hunks)
  • apps/client/src/pages/builder/sidebars/right/sections/css.tsx (1 hunks)
  • apps/client/src/pages/builder/sidebars/right/shared/section-icon.tsx (3 hunks)
  • apps/server/src/printer/printer.service.ts (1 hunks)
  • libs/schema/src/metadata/index.ts (2 hunks)
  • libs/schema/src/sample.ts (1 hunks)
  • package.json (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/client/public/styles/prism-light.css
🧰 Additional context used
🪛 Biome (1.9.4)
apps/client/public/styles/prism-dark.css

[error] 113-113: Don't use unknown media feature names.

Unexpected unknown media feature name.
You should use media feature names defined in the CSS Specifications.

(lint/correctness/noUnknownMediaFeatureName)

🔇 Additional comments (14)
apps/client/src/pages/builder/sidebars/right/shared/section-icon.tsx (1)

2-2: LGTM! Icon and type changes follow existing patterns.

The changes correctly integrate the CSS section icon by:

  1. Importing the Code icon
  2. Extending MetadataKey type
  3. Adding the CSS case to getSectionIcon

Also applies to: 23-23, 50-52

apps/client/src/pages/builder/sidebars/right/index.tsx (1)

8-8: LGTM! The CSS section is well-integrated into the sidebar.

The placement between Theme and Page sections is logical and follows the existing component structure.

Also applies to: 41-41

apps/client/public/templates/json/kakuna.json (1)

290-290: Ensure consistent CSS approach across all templates.

The change to use the universal selector * should be consistently applied across all template files. Also, consider the same selector refinement suggested earlier.

Run this script to check consistency across templates:

✅ Verification successful

CSS approach is already consistent across templates

The universal selector * and the outline styles are uniformly applied across all template files. No changes needed.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check CSS consistency across all template files
fd -e json . apps/client/public/templates/json/ -x jq -r '.metadata.css.value' {} \; | sort | uniq -c

Length of output: 190

package.json (2)

4-4: Version bump looks appropriate.

The version increment from 4.3.4 to 4.3.5 follows semantic versioning for a feature addition.


78-78: Verify the dependencies' compatibility and security.

The new dependencies added support the custom CSS feature:

  • prismjs for syntax highlighting
  • react-simple-code-editor for the code editor interface
  • @types/prismjs for TypeScript support

Run the following script to check for any known vulnerabilities or compatibility issues:

Also applies to: 219-219, 230-230

✅ Verification successful

Dependencies are secure and compatible

  • prismjs@^1.29.0 is well above all known vulnerable versions
  • react-simple-code-editor has no known vulnerabilities
  • React 18.x satisfies all peer dependency requirements
  • Type definitions are up to date
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for security advisories and compatibility issues in new dependencies

# Check for security advisories
echo "Checking security advisories for prismjs..."
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: NPM, package: "prismjs") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

echo "Checking security advisories for react-simple-code-editor..."
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: NPM, package: "react-simple-code-editor") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

# Check peer dependencies
echo "Checking peer dependencies..."
npm info [email protected] peerDependencies
npm info [email protected] peerDependencies

Length of output: 2189


Script:

#!/bin/bash
# Check exact versions of dependencies
echo "Checking package.json for exact versions..."
cat package.json | jq '.dependencies | {
  "prismjs": .prismjs,
  "react": .react,
  "react-dom": .["react-dom"]
}'

Length of output: 289

apps/client/public/templates/json/pikachu.json (1)

318-318: Same performance concern as in ditto.json

apps/client/public/styles/prism-dark.css (2)

1-21: LGTM! Well-structured base styles.

The base styles are properly structured with vendor prefixes and essential text formatting properties.


23-41: LGTM! Proper code block styling.

The code block styles provide good visual separation and readability with appropriate spacing and border-radius.

apps/client/public/templates/json/rhyhorn.json (1)

291-292: Consistent implementation across templates

The CSS changes are consistently implemented across all template files, which is good for maintainability. However, the same performance considerations apply to all templates.

Let's verify the consistency of these changes across all template files:

✅ Verification successful

CSS outline implementation verified across all templates

The CSS outline property and its visibility state are consistently implemented across all 12 template files, with identical values and disabled state, confirming good maintainability practices.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify CSS implementation consistency across all template files
# Expected: All template files should have the same CSS value and visible state

# Search for CSS value in all template files
echo "Checking CSS value consistency:"
rg -U --multiline '("css": \{[^}]+\})' 'apps/client/public/templates/json/*.json'

# Search for visible state
echo "Checking visible state consistency:"
rg '"visible": false' 'apps/client/public/templates/json/*.json'

Length of output: 466


Script:

#!/bin/bash
# First, let's find all JSON files that might be templates
echo "Looking for JSON template files:"
fd -e json . apps/client/public

# If we find files, let's examine a sample of their content
echo -e "\nChecking file contents for CSS and visible state:"
fd -e json . apps/client/public --exec head -n 20 {}

Length of output: 6921


Script:

#!/bin/bash
# Search for the specific CSS outline property and its visibility state
echo "Checking CSS outline implementation:"
rg -U --multiline '"value": "\* \{[^}]+outline[^}]+\}"' apps/client/public/templates/json/*.json -A 1

# Count total occurrences to verify consistency
echo -e "\nCounting occurrences:"
rg -c '"value": "\* \{[^}]+outline[^}]+\}"' apps/client/public/templates/json/*.json

Length of output: 4302

apps/client/public/templates/json/nosepass.json (1)

309-309: Same CSS selector concern as in onyx.json

The universal selector usage has the same implications as discussed in the onyx.json template.

apps/client/public/templates/json/chikorita.json (1)

317-317: Same CSS selector concern as in onyx.json

The universal selector usage has the same implications as discussed in the onyx.json template.

#!/bin/bash
# Description: Verify consistency of CSS changes across all template files

# Test: Check if all template files have the same CSS outline implementation
echo "Checking CSS implementation across all templates..."
rg -U --multiline 'css":\s*{\s*"value":\s*"\*\s*{[^}]*}"' apps/client/public/templates/json/
apps/client/public/templates/json/bronzor.json (1)

317-317: Same CSS selector concern as in onyx.json

The universal selector usage has the same implications as discussed in the onyx.json template.

Consider implementing a shared configuration for these debug styles to:

  1. Maintain consistency across templates
  2. Make future updates easier
  3. Allow for template-specific customizations when needed
apps/client/public/templates/json/glalie.json (1)

291-291: Consider the performance implications of using the universal selector.

The change from .section to * will apply the outline to every element in the document. While this provides better visibility for debugging, it could impact rendering performance when enabled, especially in documents with many nested elements.

Let's verify the potential impact by checking for deeply nested elements in the templates:

apps/client/public/templates/json/leafish.json (1)

292-292: LGTM! Consistent with other templates.

The CSS change maintains consistency with other template files, which is important for a unified debugging experience across different resume templates.

@@ -12,7 +12,7 @@ export const metadataSchema = z.object({
template: z.string().default("rhyhorn"),
layout: z.array(z.array(z.array(z.string()))).default(defaultLayout), // pages -> columns -> sections
css: z.object({
value: z.string().default(".section {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}"),
value: z.string().default("* {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}"),
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider using a more specific CSS selector.

The universal selector * could lead to:

  • Performance issues by affecting all elements
  • Unintended style overrides
  • Lack of style isolation between sections

Consider using a more specific selector like [data-page] .section to scope styles appropriately.

- value: z.string().default("* {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}"),
+ value: z.string().default("[data-page] .section {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}"),

Also applies to: 53-53

Comment on lines +46 to +56
<div className="rounded border p-4">
<CodeEditor
tabSize={4}
value={css.value}
className="language-css font-mono"
highlight={(code) => Prism.highlight(code, Prism.languages.css, "css")}
onValueChange={(value) => {
setValue("metadata.css.value", value);
}}
/>
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add CSS validation and security measures.

The current implementation lacks:

  1. CSS validation before applying
  2. Input size limits
  3. CSS sanitization
  4. Error handling for invalid CSS

This could lead to security vulnerabilities or broken styles.

Consider adding:

  1. CSS validation library
  2. Size limits on the input
  3. CSS sanitization
  4. Error handling for invalid CSS

Example implementation:

+ import { validateCSS } from 'css-validator';
+ import DOMPurify from 'dompurify';

  <CodeEditor
    tabSize={4}
    value={css.value}
    className="language-css font-mono"
+   maxLength={5000}
    highlight={(code) => Prism.highlight(code, Prism.languages.css, "css")}
    onValueChange={(value) => {
+     try {
+       if (value.length > 5000) {
+         throw new Error('CSS exceeds maximum length');
+       }
+       const sanitizedValue = DOMPurify.sanitize(value);
+       if (!validateCSS(sanitizedValue)) {
+         throw new Error('Invalid CSS');
+       }
        setValue("metadata.css.value", sanitizedValue);
+     } catch (error) {
+       // Handle error appropriately
+     }
    }}
  />

Committable suggestion skipped: line range outside the PR's diff.

return <Outlet />;
return (
<>
{metadata.css.visible && <style lang="css">{`[data-page] { ${metadata.css.value} }`}</style>}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Sanitize CSS before injection to prevent XSS.

Direct string interpolation of user input into a style tag is potentially dangerous. Consider sanitizing the CSS before injection.

+ import DOMPurify from 'dompurify';

- {metadata.css.visible && <style lang="css">{`[data-page] { ${metadata.css.value} }`}</style>}
+ {metadata.css.visible && (
+   <style lang="css">
+     {`[data-page] { ${DOMPurify.sanitize(metadata.css.value, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] })} }`}
+   </style>
+ )}

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +153 to +162
// Apply custom CSS if enabled
const css = resume.data.metadata.css;

if (css.visible) {
await page.evaluate((cssValue: string) => {
const styleTag = document.createElement("style");
styleTag.textContent = cssValue;
document.head.append(styleTag);
}, css.value);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add CSS sanitization to prevent security vulnerabilities.

The current implementation directly injects CSS without sanitization. This could potentially lead to CSS-based attacks (e.g., stealing data through CSS injection).

Consider adding CSS sanitization:

 if (css.visible) {
   await page.evaluate((cssValue: string) => {
     const styleTag = document.createElement("style");
-    styleTag.textContent = cssValue;
+    // Sanitize CSS before applying
+    const sanitizedCss = sanitizeCss(cssValue);
+    styleTag.textContent = sanitizedCss;
     document.head.append(styleTag);
   }, css.value);
 }

Also, consider cleaning up the injected style tag after PDF generation to prevent affecting subsequent pages:

 await page.evaluate((temporaryHtml_: string) => {
+  // Clean up injected style tag
+  document.head.querySelector('style:last-child')?.remove();
   document.body.innerHTML = temporaryHtml_;
 }, temporaryHtml);

Committable suggestion skipped: line range outside the PR's diff.

apps/client/public/styles/prism-dark.css Outdated Show resolved Hide resolved
@AmruthPillai AmruthPillai merged commit a5dc15d into main Jan 13, 2025
2 of 3 checks passed
@AmruthPillai AmruthPillai deleted the feat/custom-css branch January 13, 2025 00:07
@nicofishman
Copy link

The GOAT of resumes has brought back a needed feature! Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants