diff --git a/app/(navigation)/(code)/assets/e2b.svg b/app/(navigation)/(code)/assets/e2b.svg new file mode 100644 index 00000000..7cf3df4b --- /dev/null +++ b/app/(navigation)/(code)/assets/e2b.svg @@ -0,0 +1,6 @@ + + + diff --git a/app/(navigation)/(code)/assets/e2b/mask-group.png b/app/(navigation)/(code)/assets/e2b/mask-group.png new file mode 100644 index 00000000..4a0cbd89 Binary files /dev/null and b/app/(navigation)/(code)/assets/e2b/mask-group.png differ diff --git a/app/(navigation)/(code)/components/Frame.tsx b/app/(navigation)/(code)/components/Frame.tsx index 35fdcc87..c5d6b53f 100644 --- a/app/(navigation)/(code)/components/Frame.tsx +++ b/app/(navigation)/(code)/components/Frame.tsx @@ -11,6 +11,7 @@ import ClerkFrame from "./frames/ClerkFrame"; import CloudflareFrame from "./frames/CloudflareFrame"; import Auth0Frame from "./frames/Auth0Frame"; import DefaultFrame from "./frames/DefaultFrame"; +import E2bFrame from "./frames/E2bFrame"; import ElevenLabsFrame from "./frames/ElevenLabsFrame"; import FirecrawlFrame from "./frames/FirecrawlFrame"; import GeminiFrame from "./frames/GeminiFrame"; @@ -56,6 +57,8 @@ const Frame = ({ resize = true }: { resize?: boolean }) => { return ; case THEMES.elevenlabs.id: return ; + case THEMES.e2b.id: + return ; case THEMES.resend.id: return ; case THEMES.browserbase.id: diff --git a/app/(navigation)/(code)/components/frames/E2bFrame.module.css b/app/(navigation)/(code)/components/frames/E2bFrame.module.css new file mode 100644 index 00000000..19d9343d --- /dev/null +++ b/app/(navigation)/(code)/components/frames/E2bFrame.module.css @@ -0,0 +1,118 @@ +.frame { + --frame-background: #121212; + --selection-background: rgba(219, 68, 90, 0.4); + --selection-text-color: #ffffff; + --frame-header-background: #0a0a0a; + --frame-border: hsla(0, 0%, 100%, 0.1); + --frame-border-radius: 8px; + --frame-text-color: hsl(0, 0%, 98%); + + &.withBackground { + position: relative; + overflow: hidden; + background-color: #ff3001; + } + + &::selection { + background: var(--selection-background); + color: var(--selection-text-color); + } + + &.darkMode { + --frame-background: #121212; + --frame-header-background: #0a0a0a; + --frame-border: hsla(0, 0%, 100%, 0.1); + --frame-text-color: hsl(0, 0%, 98%); + --selection-background: rgba(219, 68, 90, 0.4); + --selection-text-color: #ffffff; + } +} + +/* Real element instead of ::after so html-to-image inlines the image on export */ +.background { + position: absolute; + z-index: 0; + top: -5%; + right: -5%; + width: 82%; + height: 82%; + background-image: url("../../assets/e2b/mask-group.png"); + background-position: top right; + background-repeat: no-repeat; + background-size: contain; + mix-blend-mode: multiply; + pointer-events: none; +} + +.window { + position: relative; + z-index: 1; + border: 0.5px solid var(--frame-border); + border-radius: var(--frame-border-radius); + -webkit-backdrop-filter: blur(3px); + backdrop-filter: blur(3px); + background: var(--frame-background); +} + +.header { + display: flex; + height: 40px; + align-items: center; + justify-content: space-between; + padding: 0 16px; + border-bottom: 1px solid var(--frame-border); + background: var(--frame-header-background); + border-top-left-radius: calc(var(--frame-border-radius) - 0.5px); + border-top-right-radius: calc(var(--frame-border-radius) - 0.5px); + gap: 12px; +} + +.fileName { + position: relative; + display: grid; + height: 40px; + align-items: center; + color: var(--frame-text-color); + font-size: 14px; + line-height: 40px; + vertical-align: top; + + input, + & > span, + &:after { + position: static; + z-index: 2; + width: auto; + min-width: 1em; + padding: 0; + border: none; + margin: 0; + appearance: none; + background: none; + font: inherit; + grid-area: 1 / 2; + resize: none; + text-align: left; + } + + & > span { + position: relative; + z-index: 1; + } + + input { + color: inherit; + } + + &:after { + content: attr(data-value) " "; + visibility: hidden; + } +} + +.language { + height: 40px; + color: #898989; + font-size: 14px; + line-height: 40px; +} diff --git a/app/(navigation)/(code)/components/frames/E2bFrame.tsx b/app/(navigation)/(code)/components/frames/E2bFrame.tsx new file mode 100644 index 00000000..05375d42 --- /dev/null +++ b/app/(navigation)/(code)/components/frames/E2bFrame.tsx @@ -0,0 +1,53 @@ +import classNames from "classnames"; +import { useAtom, useAtomValue } from "jotai"; + +import { fileNameAtom, showBackgroundAtom } from "../../store"; +import { selectedLanguageAtom } from "../../store/code"; +import { paddingAtom } from "../../store/padding"; +import { themeDarkModeAtom } from "../../store/themes"; + +import Editor from "../Editor"; +import sharedStyles from "./DefaultFrame.module.css"; +import styles from "./E2bFrame.module.css"; + +const E2bFrame = () => { + const darkMode = useAtomValue(themeDarkModeAtom); + const [padding] = useAtom(paddingAtom); + const [showBackground] = useAtom(showBackgroundAtom); + const [fileName, setFileName] = useAtom(fileNameAtom); + const selectedLanguage = useAtomValue(selectedLanguageAtom); + + return ( +
+ {!showBackground &&
} + {showBackground &&
} +
+
+
+ setFileName(event.target.value)} + spellCheck={false} + tabIndex={-1} + size={1} + /> + {fileName.length === 0 ? Untitled-1 : null} +
+ {selectedLanguage?.name} +
+ +
+
+ ); +}; + +export default E2bFrame; diff --git a/app/(navigation)/(code)/store/themes.ts b/app/(navigation)/(code)/store/themes.ts index acb7137c..0fabdaed 100644 --- a/app/(navigation)/(code)/store/themes.ts +++ b/app/(navigation)/(code)/store/themes.ts @@ -33,6 +33,8 @@ import ElevenLabsLogo from "../assets/elevenlabs.svg"; import ElevenLabsLogoUrl from "../assets/elevenlabs.svg?url"; import ResendLogo from "../assets/resend.svg"; import ResendLogoUrl from "../assets/resend.svg?url"; +import E2bLogo from "../assets/e2b.svg"; +import E2bLogoUrl from "../assets/e2b.svg?url"; import BrowserbaseLogo from "../assets/browserbase.svg"; import BrowserbaseLogoUrl from "../assets/browserbase.svg?url"; import NuxtLogo from "../assets/nuxt.svg"; @@ -556,6 +558,41 @@ export const THEMES: { [index: string]: Theme } = { }), }, }, + e2b: { + id: "e2b", + name: "E2B", + background: { + from: "#ff3001", + to: "#ff3001", + }, + icon: E2bLogo, + iconUrl: E2bLogoUrl, + font: "commit-mono", + partner: true, + lineNumbers: true, + syntax: { + dark: convertToShikiTheme({ + foreground: "#ffffff", + comment: "#585858", + keyword: "#DB445A", + constant: "#FFF", + parameter: "#ffffff", + property: "#ffffff", + function: "#FDB44D", + number: "#FDB44D", + objectLiteral: "#ffffff", + link: "#ffffff", + string: "#FF752F", + stringExpression: "#FF752F", + punctuation: "#ffffff", + highlight: "rgba(219,68,90, 0.4)", + highlightHover: "rgba(219,68,90, 0.2)", + highlightBorder: "#DB445A", + diffInserted: "#ffffff", + diffDeleted: "#DB445A", + }), + }, + }, resend: { id: "resend", name: "Resend",