feat: add support for Kotlin language and themes, enhance language detection for various programming languages
This commit is contained in:
@@ -5,6 +5,10 @@
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🖼️</text></svg>" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Code Canvas - Create Beautiful Code Images</title>
|
||||
<!-- Google Fonts: JetBrains Mono, Fira Code, Source Code Pro for code -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&family=Source+Code+Pro:wght@400;500;600;700&family=Inter:wght@400;500;600;700&family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -235,9 +235,15 @@ export const createCodeElement = (x: number, y: number): CodeElement => ({
|
||||
locked: false,
|
||||
visible: true,
|
||||
props: {
|
||||
code: '// Your code here\nconsole.log("Hello, World!");',
|
||||
language: 'javascript',
|
||||
theme: 'github-dark',
|
||||
code: `@Composable
|
||||
fun Greeting(name: String) {
|
||||
Text(
|
||||
text = "Hello, $name!",
|
||||
modifier = Modifier.padding(16.dp)
|
||||
)
|
||||
}`,
|
||||
language: 'kotlin',
|
||||
theme: 'dracula',
|
||||
fontFamily: 'JetBrains Mono',
|
||||
fontSize: 14,
|
||||
lineHeight: 1.5,
|
||||
|
||||
+30
-16
@@ -125,44 +125,58 @@ export const ASPECT_RATIOS: AspectRatio[] = [
|
||||
];
|
||||
|
||||
export const CODE_THEMES = [
|
||||
{ id: 'github-dark', name: 'GitHub Dark', bg: '#0d1117' },
|
||||
{ id: 'github-light', name: 'GitHub Light', bg: '#ffffff' },
|
||||
// IntelliJ / Android Studio themes (prioritized for Kotlin)
|
||||
{ id: 'andromeeda', name: 'Andromeeda', bg: '#23262e' },
|
||||
{ id: 'aurora-x', name: 'Aurora X', bg: '#07090f' },
|
||||
{ id: 'dark-plus', name: 'Dark+ (VS Code)', bg: '#1e1e1e' },
|
||||
{ id: 'dracula', name: 'Dracula', bg: '#282a36' },
|
||||
{ id: 'nord', name: 'Nord', bg: '#2e3440' },
|
||||
{ id: 'one-dark-pro', name: 'One Dark Pro', bg: '#282c34' },
|
||||
{ id: 'monokai', name: 'Monokai', bg: '#272822' },
|
||||
{ id: 'tokyo-night', name: 'Tokyo Night', bg: '#1a1b26' },
|
||||
{ id: 'vitesse-dark', name: 'Vitesse Dark', bg: '#121212' },
|
||||
{ id: 'vitesse-light', name: 'Vitesse Light', bg: '#ffffff' },
|
||||
{ id: 'dracula-soft', name: 'Dracula Soft', bg: '#282a36' },
|
||||
{ id: 'github-dark', name: 'GitHub Dark', bg: '#0d1117' },
|
||||
{ id: 'github-dark-dimmed', name: 'GitHub Dimmed', bg: '#22272e' },
|
||||
{ id: 'github-light', name: 'GitHub Light', bg: '#ffffff' },
|
||||
{ id: 'light-plus', name: 'Light+ (VS Code)', bg: '#ffffff' },
|
||||
{ id: 'material-theme-darker', name: 'Material Darker', bg: '#212121' },
|
||||
{ id: 'catppuccin-mocha', name: 'Catppuccin Mocha', bg: '#1e1e2e' },
|
||||
{ id: 'catppuccin-latte', name: 'Catppuccin Latte', bg: '#eff1f5' },
|
||||
{ id: 'slack-dark', name: 'Slack Dark', bg: '#222222' },
|
||||
{ id: 'poimandres', name: 'Poimandres', bg: '#1b1e28' },
|
||||
{ id: 'night-owl', name: 'Night Owl', bg: '#011627' },
|
||||
{ id: 'material-theme-ocean', name: 'Material Ocean', bg: '#0f111a' },
|
||||
{ id: 'material-theme-palenight', name: 'Material Palenight', bg: '#292d3e' },
|
||||
{ id: 'min-dark', name: 'Min Dark', bg: '#1f1f1f' },
|
||||
{ id: 'min-light', name: 'Min Light', bg: '#ffffff' },
|
||||
{ id: 'ayu-dark', name: 'Ayu Dark', bg: '#0b0e14' },
|
||||
{ id: 'monokai', name: 'Monokai', bg: '#272822' },
|
||||
{ id: 'night-owl', name: 'Night Owl', bg: '#011627' },
|
||||
{ id: 'nord', name: 'Nord', bg: '#2e3440' },
|
||||
{ id: 'one-dark-pro', name: 'One Dark Pro', bg: '#282c34' },
|
||||
{ id: 'poimandres', name: 'Poimandres', bg: '#1b1e28' },
|
||||
{ id: 'rose-pine', name: 'Rosé Pine', bg: '#191724' },
|
||||
{ id: 'rose-pine-moon', name: 'Rosé Pine Moon', bg: '#232136' },
|
||||
{ id: 'slack-dark', name: 'Slack Dark', bg: '#222222' },
|
||||
{ id: 'solarized-dark', name: 'Solarized Dark', bg: '#002b36' },
|
||||
{ id: 'solarized-light', name: 'Solarized Light', bg: '#fdf6e3' },
|
||||
{ id: 'tokyo-night', name: 'Tokyo Night', bg: '#1a1b26' },
|
||||
{ id: 'vesper', name: 'Vesper', bg: '#101010' },
|
||||
{ id: 'vitesse-dark', name: 'Vitesse Dark', bg: '#121212' },
|
||||
{ id: 'vitesse-light', name: 'Vitesse Light', bg: '#ffffff' },
|
||||
] as const;
|
||||
|
||||
export type CodeThemeId = typeof CODE_THEMES[number]['id'];
|
||||
|
||||
export const LANGUAGES = [
|
||||
'javascript',
|
||||
'typescript',
|
||||
'kotlin',
|
||||
'java',
|
||||
'typescript',
|
||||
'javascript',
|
||||
'python',
|
||||
'rust',
|
||||
'go',
|
||||
'swift',
|
||||
'dart',
|
||||
'html',
|
||||
'css',
|
||||
'json',
|
||||
'xml',
|
||||
'yaml',
|
||||
'markdown',
|
||||
'bash',
|
||||
'sql',
|
||||
'groovy',
|
||||
] as const;
|
||||
|
||||
export const FONT_FAMILIES = {
|
||||
|
||||
@@ -62,7 +62,7 @@ export function getThemeBackground(themeId: CodeThemeId): string {
|
||||
}
|
||||
|
||||
export function isLightTheme(themeId: CodeThemeId): boolean {
|
||||
const lightThemes = ['github-light', 'vitesse-light', 'catppuccin-latte', 'min-light', 'solarized-light'];
|
||||
const lightThemes = ['github-light', 'vitesse-light', 'min-light', 'solarized-light', 'light-plus'];
|
||||
return lightThemes.includes(themeId);
|
||||
}
|
||||
|
||||
@@ -81,6 +81,22 @@ export function isHighlighterReady(): boolean {
|
||||
|
||||
// Language detection based on common patterns
|
||||
export function detectLanguage(code: string): string {
|
||||
// Kotlin / Jetpack Compose patterns (check first - primary language)
|
||||
// Look for @Composable, fun, val, var, class, object, companion object, etc.
|
||||
if (/@Composable|@Preview|@OptIn|@Suppress/.test(code)) {
|
||||
return 'kotlin';
|
||||
}
|
||||
if (/^(fun|val|var|class|object|package|import|sealed|data\s+class|enum\s+class|interface)\s+/m.test(code)) {
|
||||
// Check for Kotlin-specific syntax
|
||||
if (/:\s*\w+(\s*[={()]|$|\s*,)/.test(code) ||
|
||||
/\b(Unit|String|Int|Long|Boolean|Float|Double|List|Map|Set|suspend|inline|crossinline|noinline|reified)\b/.test(code) ||
|
||||
/\bModifier\b|\bColumn\b|\bRow\b|\bBox\b|\bText\b|\bButton\b|\bScaffold\b/.test(code) ||
|
||||
/\.copy\(|\.let\s*\{|\.apply\s*\{|\.also\s*\{|\.run\s*\{/.test(code) ||
|
||||
/\blambda\b|->/.test(code)) {
|
||||
return 'kotlin';
|
||||
}
|
||||
}
|
||||
|
||||
// TypeScript/JavaScript patterns
|
||||
if (/^import\s+.*from\s+['"]|^export\s+(default\s+)?|const\s+\w+:\s*\w+/m.test(code)) {
|
||||
if (/:\s*(string|number|boolean|any|void|Promise|Array)\b/.test(code)) {
|
||||
@@ -89,15 +105,22 @@ export function detectLanguage(code: string): string {
|
||||
return 'javascript';
|
||||
}
|
||||
|
||||
// Kotlin patterns
|
||||
if (/^(fun|val|var|class|object|package|import)\s+/m.test(code) &&
|
||||
/:\s*\w+(\s*=|\s*\{|\s*\))/.test(code)) {
|
||||
return 'kotlin';
|
||||
// Java patterns (after Kotlin to avoid false positives)
|
||||
if (/^(public|private|protected)\s+(static\s+)?(class|void|int|String)/m.test(code) &&
|
||||
!/@Composable/.test(code)) {
|
||||
return 'java';
|
||||
}
|
||||
|
||||
// Java patterns
|
||||
if (/^(public|private|protected)\s+(static\s+)?(class|void|int|String)/m.test(code)) {
|
||||
return 'java';
|
||||
// Swift patterns
|
||||
if (/^(func|var|let|class|struct|enum|protocol|import\s+\w+)\s+/m.test(code) &&
|
||||
/@State|@Binding|@Published|@ObservedObject|some\s+View/.test(code)) {
|
||||
return 'swift';
|
||||
}
|
||||
|
||||
// Dart/Flutter patterns
|
||||
if (/^(class|void|final|const|import\s+')/m.test(code) &&
|
||||
/Widget|StatelessWidget|StatefulWidget|BuildContext|setState/.test(code)) {
|
||||
return 'dart';
|
||||
}
|
||||
|
||||
// Python patterns
|
||||
@@ -115,6 +138,17 @@ export function detectLanguage(code: string): string {
|
||||
return 'go';
|
||||
}
|
||||
|
||||
// Groovy/Gradle patterns
|
||||
if (/^(plugins|dependencies|android|buildscript)\s*\{/m.test(code) ||
|
||||
/implementation\s*\(|compile\s*\(/.test(code)) {
|
||||
return 'groovy';
|
||||
}
|
||||
|
||||
// XML patterns (for Android layouts)
|
||||
if (/^<\?xml|^<resources|^<layout|^<LinearLayout|^<RelativeLayout|^<ConstraintLayout|^<androidx\./m.test(code)) {
|
||||
return 'xml';
|
||||
}
|
||||
|
||||
// HTML patterns
|
||||
if (/^<!DOCTYPE|<html|<head|<body|<div/m.test(code)) {
|
||||
return 'html';
|
||||
@@ -135,6 +169,11 @@ export function detectLanguage(code: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
// YAML patterns
|
||||
if (/^[\w-]+:\s*(\n|$)|^\s+-\s+/m.test(code) && !/[{};]/.test(code)) {
|
||||
return 'yaml';
|
||||
}
|
||||
|
||||
// SQL patterns
|
||||
if (/^(SELECT|INSERT|UPDATE|DELETE|CREATE|DROP|ALTER)\s+/im.test(code)) {
|
||||
return 'sql';
|
||||
@@ -145,5 +184,5 @@ export function detectLanguage(code: string): string {
|
||||
return 'bash';
|
||||
}
|
||||
|
||||
return 'javascript'; // Default
|
||||
return 'kotlin'; // Default to Kotlin as primary language
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user