初始化项目启动器代码
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
"$schema": "../gen/schemas/desktop-schema.json",
|
"$schema": "../gen/schemas/desktop-schema.json",
|
||||||
"identifier": "default",
|
"identifier": "default",
|
||||||
"description": "Capability for the main window",
|
"description": "Capability for the main window",
|
||||||
"windows": ["welcome", "folder-*", "commit-*", "merge-*", "stash-*", "push-*", "settings"],
|
"windows": ["welcome", "folder-*", "commit-*", "merge-*", "stash-*", "push-*", "settings", "project-boot"],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"core:default",
|
"core:default",
|
||||||
"core:window:default",
|
"core:window:default",
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
"welcome",
|
"welcome",
|
||||||
"folder-*",
|
"folder-*",
|
||||||
"commit-*",
|
"commit-*",
|
||||||
"settings"
|
"settings",
|
||||||
|
"project-boot"
|
||||||
],
|
],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"window-state:default"
|
"window-state:default"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ pub mod conversations;
|
|||||||
pub mod folder_commands;
|
pub mod folder_commands;
|
||||||
pub mod folders;
|
pub mod folders;
|
||||||
pub mod mcp;
|
pub mod mcp;
|
||||||
|
pub mod project_boot;
|
||||||
pub mod system_settings;
|
pub mod system_settings;
|
||||||
pub mod terminal;
|
pub mod terminal;
|
||||||
pub mod version_control;
|
pub mod version_control;
|
||||||
|
|||||||
92
src-tauri/src/commands/project_boot.rs
Normal file
92
src-tauri/src/commands/project_boot.rs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use crate::app_error::AppCommandError;
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn create_shadcn_project(
|
||||||
|
project_name: String,
|
||||||
|
template: String,
|
||||||
|
preset_code: String,
|
||||||
|
package_manager: String,
|
||||||
|
target_dir: String,
|
||||||
|
) -> Result<String, AppCommandError> {
|
||||||
|
let project_name = project_name.trim().to_string();
|
||||||
|
let template = template.trim().to_string();
|
||||||
|
let preset_code = preset_code.trim().to_string();
|
||||||
|
let package_manager = package_manager.trim().to_string();
|
||||||
|
let target_dir = target_dir.trim().to_string();
|
||||||
|
|
||||||
|
if project_name.is_empty() {
|
||||||
|
return Err(AppCommandError::invalid_input("Project name is required"));
|
||||||
|
}
|
||||||
|
if template.is_empty() {
|
||||||
|
return Err(AppCommandError::invalid_input("Template is required"));
|
||||||
|
}
|
||||||
|
if target_dir.is_empty() {
|
||||||
|
return Err(AppCommandError::invalid_input("Target directory is required"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let full_path = PathBuf::from(&target_dir).join(&project_name);
|
||||||
|
let full_path_str = full_path.to_string_lossy().to_string();
|
||||||
|
|
||||||
|
// Check if directory already exists and is non-empty
|
||||||
|
if full_path.exists() {
|
||||||
|
let is_empty = full_path
|
||||||
|
.read_dir()
|
||||||
|
.map(|mut entries| entries.next().is_none())
|
||||||
|
.unwrap_or(false);
|
||||||
|
if !is_empty {
|
||||||
|
return Err(AppCommandError::already_exists(
|
||||||
|
"Target directory already exists and is not empty",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the command based on package manager
|
||||||
|
let (program, prefix_args): (&str, Vec<&str>) = match package_manager.as_str() {
|
||||||
|
"pnpm" => ("pnpm", vec!["dlx"]),
|
||||||
|
"yarn" => ("yarn", vec!["dlx"]),
|
||||||
|
"bun" => ("bunx", vec![]),
|
||||||
|
_ => ("npx", vec![]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut cmd = crate::process::tokio_command(program);
|
||||||
|
cmd.args(&prefix_args);
|
||||||
|
cmd.args([
|
||||||
|
"shadcn@latest",
|
||||||
|
"init",
|
||||||
|
"-n",
|
||||||
|
&project_name,
|
||||||
|
"-t",
|
||||||
|
&template,
|
||||||
|
"-p",
|
||||||
|
&preset_code,
|
||||||
|
"-y",
|
||||||
|
]);
|
||||||
|
cmd.current_dir(&target_dir);
|
||||||
|
|
||||||
|
let output = cmd.output().await.map_err(|e| {
|
||||||
|
if e.kind() == std::io::ErrorKind::NotFound {
|
||||||
|
AppCommandError::dependency_missing(format!(
|
||||||
|
"{program} is not installed. Please install Node.js first."
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
AppCommandError::external_command(
|
||||||
|
"Failed to execute project creation command",
|
||||||
|
e.to_string(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
|
||||||
|
let detail = if stderr.is_empty() { stdout } else { stderr };
|
||||||
|
return Err(AppCommandError::external_command(
|
||||||
|
"Project creation command failed",
|
||||||
|
detail,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(full_path_str)
|
||||||
|
}
|
||||||
@@ -604,3 +604,30 @@ pub async fn open_push_window(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn open_project_boot_window(app: AppHandle) -> Result<(), AppCommandError> {
|
||||||
|
if let Some(existing) = app.get_webview_window("project-boot") {
|
||||||
|
ensure_windows_undecorated(&existing);
|
||||||
|
let _ = existing.unminimize();
|
||||||
|
existing.set_focus().map_err(|e| {
|
||||||
|
AppCommandError::window("Failed to focus project boot window", e.to_string())
|
||||||
|
})?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = WebviewUrl::App("project-boot".into());
|
||||||
|
let builder = WebviewWindowBuilder::new(&app, "project-boot", url)
|
||||||
|
.title("Project Boot")
|
||||||
|
.inner_size(1400.0, 900.0)
|
||||||
|
.min_inner_size(1100.0, 700.0)
|
||||||
|
.center();
|
||||||
|
let window = apply_platform_window_style(builder)
|
||||||
|
.build()
|
||||||
|
.map_err(|e| {
|
||||||
|
AppCommandError::window("Failed to open project boot window", e.to_string())
|
||||||
|
})?;
|
||||||
|
ensure_windows_undecorated(&window);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
|||||||
use acp::manager::ConnectionManager;
|
use acp::manager::ConnectionManager;
|
||||||
use commands::{
|
use commands::{
|
||||||
acp as acp_commands, conversations, folder_commands, folders, mcp as mcp_commands,
|
acp as acp_commands, conversations, folder_commands, folders, mcp as mcp_commands,
|
||||||
notification, system_settings, terminal as terminal_commands, version_control, windows,
|
notification, project_boot, system_settings, terminal as terminal_commands, version_control,
|
||||||
|
windows,
|
||||||
};
|
};
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
use terminal::manager::TerminalManager;
|
use terminal::manager::TerminalManager;
|
||||||
@@ -268,6 +269,8 @@ pub fn run() {
|
|||||||
windows::open_merge_window,
|
windows::open_merge_window,
|
||||||
windows::open_stash_window,
|
windows::open_stash_window,
|
||||||
windows::open_push_window,
|
windows::open_push_window,
|
||||||
|
windows::open_project_boot_window,
|
||||||
|
project_boot::create_shadcn_project,
|
||||||
system_settings::get_system_proxy_settings,
|
system_settings::get_system_proxy_settings,
|
||||||
system_settings::update_system_proxy_settings,
|
system_settings::update_system_proxy_settings,
|
||||||
system_settings::get_system_language_settings,
|
system_settings::get_system_language_settings,
|
||||||
|
|||||||
41
src/app/project-boot/page.tsx
Normal file
41
src/app/project-boot/page.tsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { Suspense, useEffect } from "react"
|
||||||
|
import { useTranslations } from "next-intl"
|
||||||
|
import { AppTitleBar } from "@/components/layout/app-title-bar"
|
||||||
|
import { AppToaster } from "@/components/ui/app-toaster"
|
||||||
|
import { ProjectBootWorkspace } from "@/components/project-boot/project-boot-workspace"
|
||||||
|
|
||||||
|
function ProjectBootPageInner() {
|
||||||
|
const t = useTranslations("ProjectBoot")
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = `${t("title")} - codeg`
|
||||||
|
}, [t])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex h-screen flex-col overflow-hidden bg-background text-foreground">
|
||||||
|
<AppTitleBar
|
||||||
|
center={
|
||||||
|
<div className="text-sm font-semibold tracking-tight">
|
||||||
|
{t("title")}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<main className="min-h-0 flex-1">
|
||||||
|
<ProjectBootWorkspace />
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<AppToaster position="bottom-right" duration={6000} closeButton />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ProjectBootPage() {
|
||||||
|
return (
|
||||||
|
<Suspense>
|
||||||
|
<ProjectBootPageInner />
|
||||||
|
</Suspense>
|
||||||
|
)
|
||||||
|
}
|
||||||
28
src/components/project-boot/project-boot-workspace.tsx
Normal file
28
src/components/project-boot/project-boot-workspace.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useTranslations } from "next-intl"
|
||||||
|
import {
|
||||||
|
Tabs,
|
||||||
|
TabsList,
|
||||||
|
TabsTrigger,
|
||||||
|
TabsContent,
|
||||||
|
} from "@/components/ui/tabs"
|
||||||
|
import { ShadcnLauncher } from "./shadcn/shadcn-launcher"
|
||||||
|
|
||||||
|
export function ProjectBootWorkspace() {
|
||||||
|
const t = useTranslations("ProjectBoot")
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tabs defaultValue="shadcn" className="flex h-full flex-col">
|
||||||
|
<div className="shrink-0 border-b px-4 py-2">
|
||||||
|
<TabsList>
|
||||||
|
<TabsTrigger value="shadcn">{t("tabs.shadcn")}</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TabsContent value="shadcn" className="min-h-0 flex-1">
|
||||||
|
<ShadcnLauncher />
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
)
|
||||||
|
}
|
||||||
286
src/components/project-boot/shadcn/constants.ts
Normal file
286
src/components/project-boot/shadcn/constants.ts
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
// ── Preset encoding/decoding (matches shadcn v2 format) ─────────────
|
||||||
|
|
||||||
|
const PRESET_STYLES = [
|
||||||
|
"nova",
|
||||||
|
"vega",
|
||||||
|
"maia",
|
||||||
|
"lyra",
|
||||||
|
"mira",
|
||||||
|
] as const
|
||||||
|
|
||||||
|
const PRESET_BASE_COLORS = [
|
||||||
|
"neutral",
|
||||||
|
"stone",
|
||||||
|
"zinc",
|
||||||
|
"gray",
|
||||||
|
"mauve",
|
||||||
|
"olive",
|
||||||
|
"mist",
|
||||||
|
"taupe",
|
||||||
|
] as const
|
||||||
|
|
||||||
|
const PRESET_THEMES = [
|
||||||
|
"neutral",
|
||||||
|
"stone",
|
||||||
|
"zinc",
|
||||||
|
"gray",
|
||||||
|
"amber",
|
||||||
|
"blue",
|
||||||
|
"cyan",
|
||||||
|
"emerald",
|
||||||
|
"fuchsia",
|
||||||
|
"green",
|
||||||
|
"indigo",
|
||||||
|
"lime",
|
||||||
|
"orange",
|
||||||
|
"pink",
|
||||||
|
"purple",
|
||||||
|
"red",
|
||||||
|
"rose",
|
||||||
|
"sky",
|
||||||
|
"teal",
|
||||||
|
"violet",
|
||||||
|
"yellow",
|
||||||
|
"mauve",
|
||||||
|
"olive",
|
||||||
|
"mist",
|
||||||
|
"taupe",
|
||||||
|
] as const
|
||||||
|
|
||||||
|
const PRESET_ICON_LIBRARIES = [
|
||||||
|
"lucide",
|
||||||
|
"hugeicons",
|
||||||
|
"tabler",
|
||||||
|
"phosphor",
|
||||||
|
"remixicon",
|
||||||
|
] as const
|
||||||
|
|
||||||
|
const PRESET_FONTS = [
|
||||||
|
"inter",
|
||||||
|
"noto-sans",
|
||||||
|
"nunito-sans",
|
||||||
|
"figtree",
|
||||||
|
"roboto",
|
||||||
|
"raleway",
|
||||||
|
"dm-sans",
|
||||||
|
"public-sans",
|
||||||
|
"outfit",
|
||||||
|
"jetbrains-mono",
|
||||||
|
"geist",
|
||||||
|
"geist-mono",
|
||||||
|
"lora",
|
||||||
|
"merriweather",
|
||||||
|
"playfair-display",
|
||||||
|
"noto-serif",
|
||||||
|
"roboto-slab",
|
||||||
|
"oxanium",
|
||||||
|
"manrope",
|
||||||
|
"space-grotesk",
|
||||||
|
"montserrat",
|
||||||
|
"ibm-plex-sans",
|
||||||
|
"source-sans-3",
|
||||||
|
"instrument-sans",
|
||||||
|
] as const
|
||||||
|
|
||||||
|
const PRESET_FONT_HEADINGS = ["inherit", ...PRESET_FONTS] as const
|
||||||
|
|
||||||
|
const PRESET_RADII = [
|
||||||
|
"default",
|
||||||
|
"none",
|
||||||
|
"small",
|
||||||
|
"medium",
|
||||||
|
"large",
|
||||||
|
] as const
|
||||||
|
|
||||||
|
const PRESET_MENU_ACCENTS = ["subtle", "bold"] as const
|
||||||
|
|
||||||
|
const PRESET_MENU_COLORS = [
|
||||||
|
"default",
|
||||||
|
"inverted",
|
||||||
|
"default-translucent",
|
||||||
|
"inverted-translucent",
|
||||||
|
] as const
|
||||||
|
|
||||||
|
/** V2 field layout for bit-packing (order must match shadcn exactly) */
|
||||||
|
const PRESET_FIELDS_V2 = [
|
||||||
|
{ key: "menuColor", values: PRESET_MENU_COLORS, bits: 3 },
|
||||||
|
{ key: "menuAccent", values: PRESET_MENU_ACCENTS, bits: 3 },
|
||||||
|
{ key: "radius", values: PRESET_RADII, bits: 4 },
|
||||||
|
{ key: "font", values: PRESET_FONTS, bits: 6 },
|
||||||
|
{ key: "iconLibrary", values: PRESET_ICON_LIBRARIES, bits: 6 },
|
||||||
|
{ key: "theme", values: PRESET_THEMES, bits: 6 },
|
||||||
|
{ key: "baseColor", values: PRESET_BASE_COLORS, bits: 6 },
|
||||||
|
{ key: "style", values: PRESET_STYLES, bits: 6 },
|
||||||
|
{ key: "chartColor", values: PRESET_THEMES, bits: 6 },
|
||||||
|
{ key: "fontHeading", values: PRESET_FONT_HEADINGS, bits: 5 },
|
||||||
|
] as const
|
||||||
|
|
||||||
|
const BASE62 =
|
||||||
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||||
|
|
||||||
|
function toBase62(num: number): string {
|
||||||
|
if (num === 0) return "0"
|
||||||
|
let result = ""
|
||||||
|
let n = num
|
||||||
|
while (n > 0) {
|
||||||
|
result = BASE62[n % 62] + result
|
||||||
|
n = Math.floor(n / 62)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Encode a preset config into a compact base62 code (v2 format). */
|
||||||
|
export function encodePreset(config: PresetCodeConfig): string {
|
||||||
|
const defaults: Record<string, string> = {
|
||||||
|
menuColor: "default",
|
||||||
|
menuAccent: "subtle",
|
||||||
|
radius: "default",
|
||||||
|
font: "inter",
|
||||||
|
iconLibrary: "lucide",
|
||||||
|
theme: "neutral",
|
||||||
|
baseColor: "neutral",
|
||||||
|
style: "nova",
|
||||||
|
chartColor: config.theme ?? "neutral",
|
||||||
|
fontHeading: "inherit",
|
||||||
|
}
|
||||||
|
const merged: Record<string, string> = { ...defaults }
|
||||||
|
for (const [k, v] of Object.entries(config)) {
|
||||||
|
if (v) merged[k] = v
|
||||||
|
}
|
||||||
|
let bits = 0
|
||||||
|
let offset = 0
|
||||||
|
for (const field of PRESET_FIELDS_V2) {
|
||||||
|
const idx = (field.values as readonly string[]).indexOf(
|
||||||
|
merged[field.key] ?? ""
|
||||||
|
)
|
||||||
|
bits += (idx === -1 ? 0 : idx) * 2 ** offset
|
||||||
|
offset += field.bits
|
||||||
|
}
|
||||||
|
return "b" + toBase62(bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Config types ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** Fields that are encoded into the preset code (sent to CLI & preview). */
|
||||||
|
export interface PresetCodeConfig {
|
||||||
|
style: string
|
||||||
|
baseColor: string
|
||||||
|
theme: string
|
||||||
|
chartColor: string
|
||||||
|
iconLibrary: string
|
||||||
|
font: string
|
||||||
|
fontHeading: string
|
||||||
|
radius: string
|
||||||
|
menuAccent: string
|
||||||
|
menuColor: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Full UI config (preset fields + non-preset fields like base/template). */
|
||||||
|
export interface ShadcnPresetConfig extends PresetCodeConfig {
|
||||||
|
base: string
|
||||||
|
template: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_PRESET_CONFIG: ShadcnPresetConfig = {
|
||||||
|
base: "radix",
|
||||||
|
style: "nova",
|
||||||
|
baseColor: "neutral",
|
||||||
|
theme: "neutral",
|
||||||
|
chartColor: "neutral",
|
||||||
|
iconLibrary: "lucide",
|
||||||
|
font: "inter",
|
||||||
|
fontHeading: "inherit",
|
||||||
|
radius: "default",
|
||||||
|
menuAccent: "subtle",
|
||||||
|
menuColor: "default",
|
||||||
|
template: "start",
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── UI option arrays ────────────────────────────────────────────────
|
||||||
|
|
||||||
|
export const BASE_OPTIONS = [
|
||||||
|
{ value: "radix", label: "Radix" },
|
||||||
|
{ value: "base", label: "Base" },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const STYLE_OPTIONS = PRESET_STYLES.map((v) => ({
|
||||||
|
value: v,
|
||||||
|
label: v.charAt(0).toUpperCase() + v.slice(1),
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const BASE_COLOR_OPTIONS = PRESET_BASE_COLORS.map((v) => ({
|
||||||
|
value: v,
|
||||||
|
label: v.charAt(0).toUpperCase() + v.slice(1),
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const THEME_OPTIONS = PRESET_THEMES.map((v) => ({
|
||||||
|
value: v,
|
||||||
|
label: v.charAt(0).toUpperCase() + v.slice(1),
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const ICON_LIBRARY_OPTIONS = PRESET_ICON_LIBRARIES.map((v) => ({
|
||||||
|
value: v,
|
||||||
|
label: v.charAt(0).toUpperCase() + v.slice(1),
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const FONT_OPTIONS = PRESET_FONTS.map((v) => ({
|
||||||
|
value: v,
|
||||||
|
label: v
|
||||||
|
.split("-")
|
||||||
|
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
||||||
|
.join(" "),
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const FONT_HEADING_OPTIONS = PRESET_FONT_HEADINGS.map((v) => ({
|
||||||
|
value: v,
|
||||||
|
label:
|
||||||
|
v === "inherit"
|
||||||
|
? "Inherit"
|
||||||
|
: v
|
||||||
|
.split("-")
|
||||||
|
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
||||||
|
.join(" "),
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const MENU_ACCENT_OPTIONS = PRESET_MENU_ACCENTS.map((v) => ({
|
||||||
|
value: v,
|
||||||
|
label: v.charAt(0).toUpperCase() + v.slice(1),
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const MENU_COLOR_OPTIONS = PRESET_MENU_COLORS.map((v) => ({
|
||||||
|
value: v,
|
||||||
|
label: v
|
||||||
|
.split("-")
|
||||||
|
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
||||||
|
.join(" "),
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const RADIUS_OPTIONS = PRESET_RADII.map((v) => ({
|
||||||
|
value: v,
|
||||||
|
label: v.charAt(0).toUpperCase() + v.slice(1),
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const TEMPLATE_OPTIONS = [{ value: "start", label: "Start" }]
|
||||||
|
|
||||||
|
export const FRAMEWORK_OPTIONS = [
|
||||||
|
{ value: "next", label: "Next.js" },
|
||||||
|
{ value: "vite", label: "Vite" },
|
||||||
|
{ value: "start", label: "TanStack Start" },
|
||||||
|
{ value: "react-router", label: "React Router" },
|
||||||
|
{ value: "laravel", label: "Laravel" },
|
||||||
|
{ value: "astro", label: "Astro" },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const PACKAGE_MANAGER_OPTIONS = [
|
||||||
|
{ value: "pnpm", label: "pnpm" },
|
||||||
|
{ value: "npm", label: "npm" },
|
||||||
|
{ value: "yarn", label: "yarn" },
|
||||||
|
{ value: "bun", label: "bun" },
|
||||||
|
]
|
||||||
|
|
||||||
|
// ── URL builders ────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/** Build the preview iframe URL using a preset code. */
|
||||||
|
export function buildPreviewUrl(base: string, presetCode: string): string {
|
||||||
|
return `https://ui.shadcn.com/preview/${base}/preview?preset=${presetCode}`
|
||||||
|
}
|
||||||
201
src/components/project-boot/shadcn/create-project-dialog.tsx
Normal file
201
src/components/project-boot/shadcn/create-project-dialog.tsx
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useState } from "react"
|
||||||
|
import { useTranslations } from "next-intl"
|
||||||
|
import { Loader2, FolderOpen } from "lucide-react"
|
||||||
|
import { toast } from "sonner"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Input } from "@/components/ui/input"
|
||||||
|
import { Label } from "@/components/ui/label"
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select"
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
} from "@/components/ui/dialog"
|
||||||
|
import { openFileDialog } from "@/lib/platform"
|
||||||
|
import { createShadcnProject, openFolderWindow } from "@/lib/api"
|
||||||
|
import { FRAMEWORK_OPTIONS, PACKAGE_MANAGER_OPTIONS } from "./constants"
|
||||||
|
|
||||||
|
interface CreateProjectDialogProps {
|
||||||
|
open: boolean
|
||||||
|
onOpenChange: (open: boolean) => void
|
||||||
|
presetCode: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CreateProjectDialog({
|
||||||
|
open,
|
||||||
|
onOpenChange,
|
||||||
|
presetCode,
|
||||||
|
}: CreateProjectDialogProps) {
|
||||||
|
const t = useTranslations("ProjectBoot")
|
||||||
|
const [projectName, setProjectName] = useState("my-app")
|
||||||
|
const [framework, setFramework] = useState("next")
|
||||||
|
const [packageManager, setPackageManager] = useState("pnpm")
|
||||||
|
const [saveDirectory, setSaveDirectory] = useState("")
|
||||||
|
const [creating, setCreating] = useState(false)
|
||||||
|
const [error, setError] = useState<string | null>(null)
|
||||||
|
|
||||||
|
const handleBrowse = async () => {
|
||||||
|
const result = await openFileDialog({ directory: true, multiple: false })
|
||||||
|
if (!result) return
|
||||||
|
const selected = Array.isArray(result) ? result[0] : result
|
||||||
|
setSaveDirectory(selected)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCreate = async () => {
|
||||||
|
setError(null)
|
||||||
|
setCreating(true)
|
||||||
|
try {
|
||||||
|
const projectPath = await createShadcnProject({
|
||||||
|
projectName,
|
||||||
|
template: framework,
|
||||||
|
presetCode,
|
||||||
|
packageManager,
|
||||||
|
targetDir: saveDirectory,
|
||||||
|
})
|
||||||
|
toast.success(t("toasts.createSuccess"))
|
||||||
|
onOpenChange(false)
|
||||||
|
resetForm()
|
||||||
|
await openFolderWindow(projectPath)
|
||||||
|
} catch (err) {
|
||||||
|
const message =
|
||||||
|
err && typeof err === "object" && "message" in err
|
||||||
|
? (err as { message: string }).message
|
||||||
|
: String(err)
|
||||||
|
setError(message)
|
||||||
|
toast.error(t("toasts.createFailed"), { description: message })
|
||||||
|
} finally {
|
||||||
|
setCreating(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
setProjectName("my-app")
|
||||||
|
setFramework("next")
|
||||||
|
setPackageManager("pnpm")
|
||||||
|
setSaveDirectory("")
|
||||||
|
setError(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
const canCreate =
|
||||||
|
projectName.trim().length > 0 && saveDirectory.trim().length > 0
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={open}
|
||||||
|
onOpenChange={(v) => {
|
||||||
|
onOpenChange(v)
|
||||||
|
if (!v) resetForm()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogContent className="sm:max-w-md">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>{t("createDialog.title")}</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<div className="space-y-4 py-2">
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label>{t("createDialog.projectName")}</Label>
|
||||||
|
<Input
|
||||||
|
value={projectName}
|
||||||
|
onChange={(e) => setProjectName(e.target.value)}
|
||||||
|
placeholder={t("createDialog.projectNamePlaceholder")}
|
||||||
|
disabled={creating}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label>{t("createDialog.frameworkTemplate")}</Label>
|
||||||
|
<Select
|
||||||
|
value={framework}
|
||||||
|
onValueChange={setFramework}
|
||||||
|
disabled={creating}
|
||||||
|
>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{FRAMEWORK_OPTIONS.map((opt) => (
|
||||||
|
<SelectItem key={opt.value} value={opt.value}>
|
||||||
|
{opt.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label>{t("createDialog.packageManager")}</Label>
|
||||||
|
<Select
|
||||||
|
value={packageManager}
|
||||||
|
onValueChange={setPackageManager}
|
||||||
|
disabled={creating}
|
||||||
|
>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{PACKAGE_MANAGER_OPTIONS.map((opt) => (
|
||||||
|
<SelectItem key={opt.value} value={opt.value}>
|
||||||
|
{opt.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label>{t("createDialog.saveDirectory")}</Label>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Input
|
||||||
|
value={saveDirectory}
|
||||||
|
onChange={(e) => setSaveDirectory(e.target.value)}
|
||||||
|
placeholder={t("createDialog.saveDirectoryPlaceholder")}
|
||||||
|
disabled={creating}
|
||||||
|
className="flex-1"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={handleBrowse}
|
||||||
|
disabled={creating}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<FolderOpen className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{error && (
|
||||||
|
<div className="rounded-lg border border-destructive/50 bg-destructive/10 px-3 py-2 text-sm text-destructive">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DialogFooter>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => onOpenChange(false)}
|
||||||
|
disabled={creating}
|
||||||
|
>
|
||||||
|
{t("createDialog.cancel")}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleCreate} disabled={!canCreate || creating}>
|
||||||
|
{creating && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||||
|
{creating ? t("createDialog.creating") : t("createDialog.create")}
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
128
src/components/project-boot/shadcn/shadcn-config-panel.tsx
Normal file
128
src/components/project-boot/shadcn/shadcn-config-panel.tsx
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useState } from "react"
|
||||||
|
import { useTranslations } from "next-intl"
|
||||||
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { Label } from "@/components/ui/label"
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select"
|
||||||
|
import { ScrollArea } from "@/components/ui/scroll-area"
|
||||||
|
import {
|
||||||
|
BASE_OPTIONS,
|
||||||
|
STYLE_OPTIONS,
|
||||||
|
BASE_COLOR_OPTIONS,
|
||||||
|
THEME_OPTIONS,
|
||||||
|
ICON_LIBRARY_OPTIONS,
|
||||||
|
FONT_OPTIONS,
|
||||||
|
FONT_HEADING_OPTIONS,
|
||||||
|
MENU_ACCENT_OPTIONS,
|
||||||
|
MENU_COLOR_OPTIONS,
|
||||||
|
RADIUS_OPTIONS,
|
||||||
|
TEMPLATE_OPTIONS,
|
||||||
|
type ShadcnPresetConfig,
|
||||||
|
} from "./constants"
|
||||||
|
import { CreateProjectDialog } from "./create-project-dialog"
|
||||||
|
|
||||||
|
interface ShadcnConfigPanelProps {
|
||||||
|
config: ShadcnPresetConfig
|
||||||
|
onConfigChange: (key: keyof ShadcnPresetConfig, value: string) => void
|
||||||
|
presetCode: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfigI18nKey =
|
||||||
|
| "config.base"
|
||||||
|
| "config.style"
|
||||||
|
| "config.baseColor"
|
||||||
|
| "config.theme"
|
||||||
|
| "config.chartColor"
|
||||||
|
| "config.iconLibrary"
|
||||||
|
| "config.font"
|
||||||
|
| "config.fontHeading"
|
||||||
|
| "config.menuAccent"
|
||||||
|
| "config.menuColor"
|
||||||
|
| "config.radius"
|
||||||
|
| "config.template"
|
||||||
|
|
||||||
|
const CONFIG_FIELDS: {
|
||||||
|
key: keyof ShadcnPresetConfig
|
||||||
|
i18nKey: ConfigI18nKey
|
||||||
|
options: { value: string; label: string }[]
|
||||||
|
}[] = [
|
||||||
|
{ key: "base", i18nKey: "config.base", options: BASE_OPTIONS },
|
||||||
|
{ key: "style", i18nKey: "config.style", options: STYLE_OPTIONS },
|
||||||
|
{ key: "baseColor", i18nKey: "config.baseColor", options: BASE_COLOR_OPTIONS },
|
||||||
|
{ key: "theme", i18nKey: "config.theme", options: THEME_OPTIONS },
|
||||||
|
{ key: "chartColor", i18nKey: "config.chartColor", options: THEME_OPTIONS },
|
||||||
|
{
|
||||||
|
key: "iconLibrary",
|
||||||
|
i18nKey: "config.iconLibrary",
|
||||||
|
options: ICON_LIBRARY_OPTIONS,
|
||||||
|
},
|
||||||
|
{ key: "font", i18nKey: "config.font", options: FONT_OPTIONS },
|
||||||
|
{
|
||||||
|
key: "fontHeading",
|
||||||
|
i18nKey: "config.fontHeading",
|
||||||
|
options: FONT_HEADING_OPTIONS,
|
||||||
|
},
|
||||||
|
{ key: "menuAccent", i18nKey: "config.menuAccent", options: MENU_ACCENT_OPTIONS },
|
||||||
|
{ key: "menuColor", i18nKey: "config.menuColor", options: MENU_COLOR_OPTIONS },
|
||||||
|
{ key: "radius", i18nKey: "config.radius", options: RADIUS_OPTIONS },
|
||||||
|
{ key: "template", i18nKey: "config.template", options: TEMPLATE_OPTIONS },
|
||||||
|
]
|
||||||
|
|
||||||
|
export function ShadcnConfigPanel({
|
||||||
|
config,
|
||||||
|
onConfigChange,
|
||||||
|
presetCode,
|
||||||
|
}: ShadcnConfigPanelProps) {
|
||||||
|
const t = useTranslations("ProjectBoot")
|
||||||
|
const [createOpen, setCreateOpen] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex h-full flex-col">
|
||||||
|
<ScrollArea className="flex-1 px-4 py-3">
|
||||||
|
<div className="space-y-3">
|
||||||
|
{CONFIG_FIELDS.map((field) => (
|
||||||
|
<div key={field.key} className="space-y-1">
|
||||||
|
<Label className="text-xs text-muted-foreground">
|
||||||
|
{t(field.i18nKey)}
|
||||||
|
</Label>
|
||||||
|
<Select
|
||||||
|
value={config[field.key]}
|
||||||
|
onValueChange={(v) => onConfigChange(field.key, v)}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="h-8">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{field.options.map((opt) => (
|
||||||
|
<SelectItem key={opt.value} value={opt.value}>
|
||||||
|
{opt.label}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
|
||||||
|
<div className="shrink-0 border-t px-4 py-3">
|
||||||
|
<Button className="w-full" onClick={() => setCreateOpen(true)}>
|
||||||
|
{t("config.createProject")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<CreateProjectDialog
|
||||||
|
open={createOpen}
|
||||||
|
onOpenChange={setCreateOpen}
|
||||||
|
presetCode={presetCode}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
50
src/components/project-boot/shadcn/shadcn-launcher.tsx
Normal file
50
src/components/project-boot/shadcn/shadcn-launcher.tsx
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useMemo, useState } from "react"
|
||||||
|
import {
|
||||||
|
ResizablePanelGroup,
|
||||||
|
ResizablePanel,
|
||||||
|
ResizableHandle,
|
||||||
|
} from "@/components/ui/resizable"
|
||||||
|
import { ShadcnConfigPanel } from "./shadcn-config-panel"
|
||||||
|
import { ShadcnPreview } from "./shadcn-preview"
|
||||||
|
import {
|
||||||
|
DEFAULT_PRESET_CONFIG,
|
||||||
|
encodePreset,
|
||||||
|
buildPreviewUrl,
|
||||||
|
type ShadcnPresetConfig,
|
||||||
|
} from "./constants"
|
||||||
|
|
||||||
|
export function ShadcnLauncher() {
|
||||||
|
const [config, setConfig] = useState<ShadcnPresetConfig>(
|
||||||
|
DEFAULT_PRESET_CONFIG
|
||||||
|
)
|
||||||
|
|
||||||
|
const presetCode = useMemo(() => encodePreset(config), [config])
|
||||||
|
const previewUrl = useMemo(
|
||||||
|
() => buildPreviewUrl(config.base, presetCode),
|
||||||
|
[config.base, presetCode]
|
||||||
|
)
|
||||||
|
|
||||||
|
const updateConfig = (key: keyof ShadcnPresetConfig, value: string) => {
|
||||||
|
setConfig((prev) => ({ ...prev, [key]: value }))
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ResizablePanelGroup direction="horizontal" className="h-full">
|
||||||
|
<ResizablePanel defaultSize={40} minSize={30} maxSize={50}>
|
||||||
|
<ShadcnConfigPanel
|
||||||
|
config={config}
|
||||||
|
onConfigChange={updateConfig}
|
||||||
|
presetCode={presetCode}
|
||||||
|
/>
|
||||||
|
</ResizablePanel>
|
||||||
|
|
||||||
|
<ResizableHandle />
|
||||||
|
|
||||||
|
<ResizablePanel defaultSize={60} minSize={40}>
|
||||||
|
<ShadcnPreview previewUrl={previewUrl} />
|
||||||
|
</ResizablePanel>
|
||||||
|
</ResizablePanelGroup>
|
||||||
|
)
|
||||||
|
}
|
||||||
51
src/components/project-boot/shadcn/shadcn-preview.tsx
Normal file
51
src/components/project-boot/shadcn/shadcn-preview.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useEffect, useRef, useState } from "react"
|
||||||
|
import { useTranslations } from "next-intl"
|
||||||
|
import { Loader2 } from "lucide-react"
|
||||||
|
|
||||||
|
interface ShadcnPreviewProps {
|
||||||
|
previewUrl: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ShadcnPreview({ previewUrl }: ShadcnPreviewProps) {
|
||||||
|
const t = useTranslations("ProjectBoot")
|
||||||
|
const [debouncedUrl, setDebouncedUrl] = useState(previewUrl)
|
||||||
|
const [loading, setLoading] = useState(true)
|
||||||
|
const timerRef = useRef<ReturnType<typeof setTimeout>>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (timerRef.current) {
|
||||||
|
clearTimeout(timerRef.current)
|
||||||
|
}
|
||||||
|
timerRef.current = setTimeout(() => {
|
||||||
|
setDebouncedUrl(previewUrl)
|
||||||
|
setLoading(true)
|
||||||
|
}, 500)
|
||||||
|
return () => {
|
||||||
|
if (timerRef.current) {
|
||||||
|
clearTimeout(timerRef.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [previewUrl])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative h-full w-full">
|
||||||
|
{loading && (
|
||||||
|
<div className="absolute inset-0 z-10 flex items-center justify-center bg-background/80">
|
||||||
|
<Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
|
||||||
|
<span className="ml-2 text-sm text-muted-foreground">
|
||||||
|
{t("preview.loading")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<iframe
|
||||||
|
key={debouncedUrl}
|
||||||
|
src={debouncedUrl}
|
||||||
|
className="h-full w-full border-0"
|
||||||
|
onLoad={() => setLoading(false)}
|
||||||
|
sandbox="allow-scripts allow-same-origin allow-popups"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import { FolderOpen, GitBranch } from "lucide-react"
|
import { FolderOpen, GitBranch, Rocket } from "lucide-react"
|
||||||
import { useTranslations } from "next-intl"
|
import { useTranslations } from "next-intl"
|
||||||
import { toast } from "sonner"
|
import { toast } from "sonner"
|
||||||
import { openFolderWindow } from "@/lib/api"
|
import { openFolderWindow, openProjectBootWindow } from "@/lib/api"
|
||||||
import { openFileDialog } from "@/lib/platform"
|
import { openFileDialog } from "@/lib/platform"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { CloneDialog } from "./clone-dialog"
|
import { CloneDialog } from "./clone-dialog"
|
||||||
@@ -51,6 +51,23 @@ export function FolderActions() {
|
|||||||
{t("cloneRepository")}
|
{t("cloneRepository")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className="justify-start gap-2 h-9"
|
||||||
|
onClick={async () => {
|
||||||
|
try {
|
||||||
|
await openProjectBootWindow()
|
||||||
|
} catch (err) {
|
||||||
|
console.error("[FolderActions] failed to open project boot:", err)
|
||||||
|
toast.error(t("toasts.openProjectBootFailed"))
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<Rocket className="h-4 w-4" />
|
||||||
|
{t("projectBoot")}
|
||||||
|
</Button>
|
||||||
|
|
||||||
<CloneDialog open={cloneOpen} onOpenChange={setCloneOpen} />
|
<CloneDialog open={cloneOpen} onOpenChange={setCloneOpen} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -21,13 +21,15 @@
|
|||||||
"removeFromHistory": "إزالة من السجل",
|
"removeFromHistory": "إزالة من السجل",
|
||||||
"openFolder": "فتح مجلد",
|
"openFolder": "فتح مجلد",
|
||||||
"cloneRepository": "استنساخ المستودع",
|
"cloneRepository": "استنساخ المستودع",
|
||||||
|
"projectBoot": "مُنشئ المشروع",
|
||||||
"softwareVersion": "الإصدار {version}",
|
"softwareVersion": "الإصدار {version}",
|
||||||
"toasts": {
|
"toasts": {
|
||||||
"loadFolderHistoryFailed": "فشل تحميل سجل المجلدات",
|
"loadFolderHistoryFailed": "فشل تحميل سجل المجلدات",
|
||||||
"openFolderFailed": "فشل فتح المجلد",
|
"openFolderFailed": "فشل فتح المجلد",
|
||||||
"removeFromHistoryFailed": "فشل إزالة المجلد من السجل",
|
"removeFromHistoryFailed": "فشل إزالة المجلد من السجل",
|
||||||
"openSettingsFailed": "فشل فتح الإعدادات",
|
"openSettingsFailed": "فشل فتح الإعدادات",
|
||||||
"cloneFailed": "فشل استنساخ المستودع"
|
"cloneFailed": "فشل استنساخ المستودع",
|
||||||
|
"openProjectBootFailed": "فشل فتح مُنشئ المشروع"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"unknown": "حدث خطأ غير متوقع",
|
"unknown": "حدث خطأ غير متوقع",
|
||||||
@@ -1571,5 +1573,50 @@
|
|||||||
"loadingHunk": "جارٍ تحميل hunk...",
|
"loadingHunk": "جارٍ تحميل hunk...",
|
||||||
"noDiffData": "لا توجد بيانات diff"
|
"noDiffData": "لا توجد بيانات diff"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ProjectBoot": {
|
||||||
|
"title": "مُنشئ المشروع",
|
||||||
|
"tabs": {
|
||||||
|
"shadcn": "shadcn"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"base": "الأساس",
|
||||||
|
"style": "النمط",
|
||||||
|
"baseColor": "اللون الأساسي",
|
||||||
|
"theme": "السمة",
|
||||||
|
"chartColor": "لون المخطط",
|
||||||
|
"iconLibrary": "مكتبة الأيقونات",
|
||||||
|
"font": "الخط",
|
||||||
|
"fontHeading": "خط العنوان",
|
||||||
|
"menuAccent": "تمييز القائمة",
|
||||||
|
"menuColor": "لون القائمة",
|
||||||
|
"radius": "نصف القطر",
|
||||||
|
"template": "القالب",
|
||||||
|
"createProject": "إنشاء مشروع"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"loading": "جاري تحميل المعاينة..."
|
||||||
|
},
|
||||||
|
"createDialog": {
|
||||||
|
"title": "إنشاء مشروع",
|
||||||
|
"projectName": "اسم المشروع",
|
||||||
|
"projectNamePlaceholder": "my-app",
|
||||||
|
"frameworkTemplate": "قالب الإطار",
|
||||||
|
"packageManager": "مدير الحزم",
|
||||||
|
"saveDirectory": "دليل الحفظ",
|
||||||
|
"saveDirectoryPlaceholder": "اختر الدليل...",
|
||||||
|
"browseDirectory": "تصفح",
|
||||||
|
"cancel": "إلغاء",
|
||||||
|
"create": "إنشاء",
|
||||||
|
"creating": "جاري إنشاء المشروع..."
|
||||||
|
},
|
||||||
|
"toasts": {
|
||||||
|
"createFailed": "فشل إنشاء المشروع",
|
||||||
|
"createSuccess": "تم إنشاء المشروع بنجاح"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"directoryExists": "الدليل موجود بالفعل وليس فارغاً.",
|
||||||
|
"commandFailed": "فشل أمر إنشاء المشروع."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,15 @@
|
|||||||
"removeFromHistory": "Aus Verlauf entfernen",
|
"removeFromHistory": "Aus Verlauf entfernen",
|
||||||
"openFolder": "Ordner öffnen",
|
"openFolder": "Ordner öffnen",
|
||||||
"cloneRepository": "Repository klonen",
|
"cloneRepository": "Repository klonen",
|
||||||
|
"projectBoot": "Projekt-Starter",
|
||||||
"softwareVersion": "Version {version}",
|
"softwareVersion": "Version {version}",
|
||||||
"toasts": {
|
"toasts": {
|
||||||
"loadFolderHistoryFailed": "Ordnerverlauf konnte nicht geladen werden",
|
"loadFolderHistoryFailed": "Ordnerverlauf konnte nicht geladen werden",
|
||||||
"openFolderFailed": "Ordner konnte nicht geöffnet werden",
|
"openFolderFailed": "Ordner konnte nicht geöffnet werden",
|
||||||
"removeFromHistoryFailed": "Ordner konnte nicht entfernt werden",
|
"removeFromHistoryFailed": "Ordner konnte nicht entfernt werden",
|
||||||
"openSettingsFailed": "Einstellungen konnten nicht geöffnet werden",
|
"openSettingsFailed": "Einstellungen konnten nicht geöffnet werden",
|
||||||
"cloneFailed": "Repository konnte nicht geklont werden"
|
"cloneFailed": "Repository konnte nicht geklont werden",
|
||||||
|
"openProjectBootFailed": "Projekt-Starter konnte nicht geöffnet werden"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"unknown": "Unerwarteter Fehler",
|
"unknown": "Unerwarteter Fehler",
|
||||||
@@ -1571,5 +1573,50 @@
|
|||||||
"loadingHunk": "Hunk wird geladen...",
|
"loadingHunk": "Hunk wird geladen...",
|
||||||
"noDiffData": "Keine Diff-Daten"
|
"noDiffData": "Keine Diff-Daten"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ProjectBoot": {
|
||||||
|
"title": "Projekt-Starter",
|
||||||
|
"tabs": {
|
||||||
|
"shadcn": "shadcn"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"base": "Basis",
|
||||||
|
"style": "Stil",
|
||||||
|
"baseColor": "Basisfarbe",
|
||||||
|
"theme": "Thema",
|
||||||
|
"chartColor": "Diagrammfarbe",
|
||||||
|
"iconLibrary": "Icon-Bibliothek",
|
||||||
|
"font": "Schriftart",
|
||||||
|
"fontHeading": "Überschrift-Schriftart",
|
||||||
|
"menuAccent": "Menü-Akzent",
|
||||||
|
"menuColor": "Menü-Farbe",
|
||||||
|
"radius": "Radius",
|
||||||
|
"template": "Vorlage",
|
||||||
|
"createProject": "Projekt erstellen"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"loading": "Vorschau wird geladen..."
|
||||||
|
},
|
||||||
|
"createDialog": {
|
||||||
|
"title": "Projekt erstellen",
|
||||||
|
"projectName": "Projektname",
|
||||||
|
"projectNamePlaceholder": "my-app",
|
||||||
|
"frameworkTemplate": "Framework-Vorlage",
|
||||||
|
"packageManager": "Paketmanager",
|
||||||
|
"saveDirectory": "Speicherverzeichnis",
|
||||||
|
"saveDirectoryPlaceholder": "Verzeichnis auswählen...",
|
||||||
|
"browseDirectory": "Durchsuchen",
|
||||||
|
"cancel": "Abbrechen",
|
||||||
|
"create": "Erstellen",
|
||||||
|
"creating": "Projekt wird erstellt..."
|
||||||
|
},
|
||||||
|
"toasts": {
|
||||||
|
"createFailed": "Projekt konnte nicht erstellt werden",
|
||||||
|
"createSuccess": "Projekt erfolgreich erstellt"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"directoryExists": "Verzeichnis existiert bereits und ist nicht leer.",
|
||||||
|
"commandFailed": "Projekterstellungsbefehl fehlgeschlagen."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,15 @@
|
|||||||
"removeFromHistory": "Remove from history",
|
"removeFromHistory": "Remove from history",
|
||||||
"openFolder": "Open Folder",
|
"openFolder": "Open Folder",
|
||||||
"cloneRepository": "Clone Repository",
|
"cloneRepository": "Clone Repository",
|
||||||
|
"projectBoot": "Project Boot",
|
||||||
"softwareVersion": "version {version}",
|
"softwareVersion": "version {version}",
|
||||||
"toasts": {
|
"toasts": {
|
||||||
"loadFolderHistoryFailed": "Failed to load folder history",
|
"loadFolderHistoryFailed": "Failed to load folder history",
|
||||||
"openFolderFailed": "Failed to open folder",
|
"openFolderFailed": "Failed to open folder",
|
||||||
"removeFromHistoryFailed": "Failed to remove folder",
|
"removeFromHistoryFailed": "Failed to remove folder",
|
||||||
"openSettingsFailed": "Failed to open settings",
|
"openSettingsFailed": "Failed to open settings",
|
||||||
"cloneFailed": "Failed to clone repository"
|
"cloneFailed": "Failed to clone repository",
|
||||||
|
"openProjectBootFailed": "Failed to open Project Boot"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"unknown": "Unexpected error",
|
"unknown": "Unexpected error",
|
||||||
@@ -1571,5 +1573,50 @@
|
|||||||
"loadingHunk": "Loading hunk...",
|
"loadingHunk": "Loading hunk...",
|
||||||
"noDiffData": "No diff data"
|
"noDiffData": "No diff data"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ProjectBoot": {
|
||||||
|
"title": "Project Boot",
|
||||||
|
"tabs": {
|
||||||
|
"shadcn": "shadcn"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"base": "Base",
|
||||||
|
"style": "Style",
|
||||||
|
"baseColor": "Base Color",
|
||||||
|
"theme": "Theme",
|
||||||
|
"chartColor": "Chart Color",
|
||||||
|
"iconLibrary": "Icon Library",
|
||||||
|
"font": "Font",
|
||||||
|
"fontHeading": "Heading Font",
|
||||||
|
"menuAccent": "Menu Accent",
|
||||||
|
"menuColor": "Menu Color",
|
||||||
|
"radius": "Radius",
|
||||||
|
"template": "Template",
|
||||||
|
"createProject": "Create Project"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"loading": "Loading preview..."
|
||||||
|
},
|
||||||
|
"createDialog": {
|
||||||
|
"title": "Create Project",
|
||||||
|
"projectName": "Project Name",
|
||||||
|
"projectNamePlaceholder": "my-app",
|
||||||
|
"frameworkTemplate": "Framework Template",
|
||||||
|
"packageManager": "Package Manager",
|
||||||
|
"saveDirectory": "Save Directory",
|
||||||
|
"saveDirectoryPlaceholder": "Select directory...",
|
||||||
|
"browseDirectory": "Browse",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"create": "Create",
|
||||||
|
"creating": "Creating project..."
|
||||||
|
},
|
||||||
|
"toasts": {
|
||||||
|
"createFailed": "Failed to create project",
|
||||||
|
"createSuccess": "Project created successfully"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"directoryExists": "Directory already exists and is not empty.",
|
||||||
|
"commandFailed": "Project creation command failed."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,15 @@
|
|||||||
"removeFromHistory": "Quitar del historial",
|
"removeFromHistory": "Quitar del historial",
|
||||||
"openFolder": "Abrir carpeta",
|
"openFolder": "Abrir carpeta",
|
||||||
"cloneRepository": "Clonar repositorio",
|
"cloneRepository": "Clonar repositorio",
|
||||||
|
"projectBoot": "Inicio de Proyecto",
|
||||||
"softwareVersion": "versión {version}",
|
"softwareVersion": "versión {version}",
|
||||||
"toasts": {
|
"toasts": {
|
||||||
"loadFolderHistoryFailed": "No se pudo cargar el historial de carpetas",
|
"loadFolderHistoryFailed": "No se pudo cargar el historial de carpetas",
|
||||||
"openFolderFailed": "No se pudo abrir la carpeta",
|
"openFolderFailed": "No se pudo abrir la carpeta",
|
||||||
"removeFromHistoryFailed": "No se pudo quitar la carpeta",
|
"removeFromHistoryFailed": "No se pudo quitar la carpeta",
|
||||||
"openSettingsFailed": "No se pudo abrir la configuración",
|
"openSettingsFailed": "No se pudo abrir la configuración",
|
||||||
"cloneFailed": "No se pudo clonar el repositorio"
|
"cloneFailed": "No se pudo clonar el repositorio",
|
||||||
|
"openProjectBootFailed": "Error al abrir el inicio de proyecto"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"unknown": "Error inesperado",
|
"unknown": "Error inesperado",
|
||||||
@@ -1571,5 +1573,50 @@
|
|||||||
"loadingHunk": "Cargando hunk...",
|
"loadingHunk": "Cargando hunk...",
|
||||||
"noDiffData": "Sin datos de diff"
|
"noDiffData": "Sin datos de diff"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ProjectBoot": {
|
||||||
|
"title": "Inicio de Proyecto",
|
||||||
|
"tabs": {
|
||||||
|
"shadcn": "shadcn"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"base": "Base",
|
||||||
|
"style": "Estilo",
|
||||||
|
"baseColor": "Color base",
|
||||||
|
"theme": "Tema",
|
||||||
|
"chartColor": "Color del gráfico",
|
||||||
|
"iconLibrary": "Biblioteca de iconos",
|
||||||
|
"font": "Fuente",
|
||||||
|
"fontHeading": "Fuente de título",
|
||||||
|
"menuAccent": "Acento del menú",
|
||||||
|
"menuColor": "Color del menú",
|
||||||
|
"radius": "Radio",
|
||||||
|
"template": "Plantilla",
|
||||||
|
"createProject": "Crear proyecto"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"loading": "Cargando vista previa..."
|
||||||
|
},
|
||||||
|
"createDialog": {
|
||||||
|
"title": "Crear proyecto",
|
||||||
|
"projectName": "Nombre del proyecto",
|
||||||
|
"projectNamePlaceholder": "my-app",
|
||||||
|
"frameworkTemplate": "Plantilla del framework",
|
||||||
|
"packageManager": "Gestor de paquetes",
|
||||||
|
"saveDirectory": "Directorio de guardado",
|
||||||
|
"saveDirectoryPlaceholder": "Seleccionar directorio...",
|
||||||
|
"browseDirectory": "Explorar",
|
||||||
|
"cancel": "Cancelar",
|
||||||
|
"create": "Crear",
|
||||||
|
"creating": "Creando proyecto..."
|
||||||
|
},
|
||||||
|
"toasts": {
|
||||||
|
"createFailed": "Error al crear el proyecto",
|
||||||
|
"createSuccess": "Proyecto creado exitosamente"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"directoryExists": "El directorio ya existe y no está vacío.",
|
||||||
|
"commandFailed": "El comando de creación del proyecto falló."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,15 @@
|
|||||||
"removeFromHistory": "Retirer de l’historique",
|
"removeFromHistory": "Retirer de l’historique",
|
||||||
"openFolder": "Ouvrir un dossier",
|
"openFolder": "Ouvrir un dossier",
|
||||||
"cloneRepository": "Cloner un dépôt",
|
"cloneRepository": "Cloner un dépôt",
|
||||||
|
"projectBoot": "Lanceur de projet",
|
||||||
"softwareVersion": "Version {version}",
|
"softwareVersion": "Version {version}",
|
||||||
"toasts": {
|
"toasts": {
|
||||||
"loadFolderHistoryFailed": "Échec du chargement de l’historique des dossiers",
|
"loadFolderHistoryFailed": "Échec du chargement de l’historique des dossiers",
|
||||||
"openFolderFailed": "Échec de l’ouverture du dossier",
|
"openFolderFailed": "Échec de l’ouverture du dossier",
|
||||||
"removeFromHistoryFailed": "Échec de la suppression du dossier",
|
"removeFromHistoryFailed": "Échec de la suppression du dossier",
|
||||||
"openSettingsFailed": "Échec de l’ouverture des paramètres",
|
"openSettingsFailed": "Échec de l’ouverture des paramètres",
|
||||||
"cloneFailed": "Échec du clonage du dépôt"
|
"cloneFailed": "Échec du clonage du dépôt",
|
||||||
|
"openProjectBootFailed": "Impossible d'ouvrir le lanceur de projet"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"unknown": "Erreur inattendue",
|
"unknown": "Erreur inattendue",
|
||||||
@@ -1571,5 +1573,50 @@
|
|||||||
"loadingHunk": "Chargement du hunk...",
|
"loadingHunk": "Chargement du hunk...",
|
||||||
"noDiffData": "Aucune donnée diff"
|
"noDiffData": "Aucune donnée diff"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ProjectBoot": {
|
||||||
|
"title": "Lanceur de projet",
|
||||||
|
"tabs": {
|
||||||
|
"shadcn": "shadcn"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"base": "Base",
|
||||||
|
"style": "Style",
|
||||||
|
"baseColor": "Couleur de base",
|
||||||
|
"theme": "Thème",
|
||||||
|
"chartColor": "Couleur du graphique",
|
||||||
|
"iconLibrary": "Bibliothèque d'icônes",
|
||||||
|
"font": "Police",
|
||||||
|
"fontHeading": "Police de titre",
|
||||||
|
"menuAccent": "Accent du menu",
|
||||||
|
"menuColor": "Couleur du menu",
|
||||||
|
"radius": "Rayon",
|
||||||
|
"template": "Modèle",
|
||||||
|
"createProject": "Créer un projet"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"loading": "Chargement de l'aperçu..."
|
||||||
|
},
|
||||||
|
"createDialog": {
|
||||||
|
"title": "Créer un projet",
|
||||||
|
"projectName": "Nom du projet",
|
||||||
|
"projectNamePlaceholder": "my-app",
|
||||||
|
"frameworkTemplate": "Modèle de framework",
|
||||||
|
"packageManager": "Gestionnaire de paquets",
|
||||||
|
"saveDirectory": "Répertoire de sauvegarde",
|
||||||
|
"saveDirectoryPlaceholder": "Sélectionner un répertoire...",
|
||||||
|
"browseDirectory": "Parcourir",
|
||||||
|
"cancel": "Annuler",
|
||||||
|
"create": "Créer",
|
||||||
|
"creating": "Création du projet..."
|
||||||
|
},
|
||||||
|
"toasts": {
|
||||||
|
"createFailed": "Échec de la création du projet",
|
||||||
|
"createSuccess": "Projet créé avec succès"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"directoryExists": "Le répertoire existe déjà et n'est pas vide.",
|
||||||
|
"commandFailed": "La commande de création du projet a échoué."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,15 @@
|
|||||||
"removeFromHistory": "履歴から削除",
|
"removeFromHistory": "履歴から削除",
|
||||||
"openFolder": "フォルダを開く",
|
"openFolder": "フォルダを開く",
|
||||||
"cloneRepository": "リポジトリをクローン",
|
"cloneRepository": "リポジトリをクローン",
|
||||||
|
"projectBoot": "プロジェクトブート",
|
||||||
"softwareVersion": "バージョン {version}",
|
"softwareVersion": "バージョン {version}",
|
||||||
"toasts": {
|
"toasts": {
|
||||||
"loadFolderHistoryFailed": "フォルダ履歴の読み込みに失敗しました",
|
"loadFolderHistoryFailed": "フォルダ履歴の読み込みに失敗しました",
|
||||||
"openFolderFailed": "フォルダを開けませんでした",
|
"openFolderFailed": "フォルダを開けませんでした",
|
||||||
"removeFromHistoryFailed": "履歴からの削除に失敗しました",
|
"removeFromHistoryFailed": "履歴からの削除に失敗しました",
|
||||||
"openSettingsFailed": "設定を開けませんでした",
|
"openSettingsFailed": "設定を開けませんでした",
|
||||||
"cloneFailed": "リポジトリのクローンに失敗しました"
|
"cloneFailed": "リポジトリのクローンに失敗しました",
|
||||||
|
"openProjectBootFailed": "プロジェクトブートを開けませんでした"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"unknown": "予期しないエラーが発生しました",
|
"unknown": "予期しないエラーが発生しました",
|
||||||
@@ -1571,5 +1573,50 @@
|
|||||||
"loadingHunk": "Hunk を読み込み中...",
|
"loadingHunk": "Hunk を読み込み中...",
|
||||||
"noDiffData": "Diff データがありません"
|
"noDiffData": "Diff データがありません"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ProjectBoot": {
|
||||||
|
"title": "プロジェクトブート",
|
||||||
|
"tabs": {
|
||||||
|
"shadcn": "shadcn"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"base": "ベース",
|
||||||
|
"style": "スタイル",
|
||||||
|
"baseColor": "ベースカラー",
|
||||||
|
"theme": "テーマ",
|
||||||
|
"chartColor": "チャートカラー",
|
||||||
|
"iconLibrary": "アイコンライブラリ",
|
||||||
|
"font": "フォント",
|
||||||
|
"fontHeading": "見出しフォント",
|
||||||
|
"menuAccent": "メニューアクセント",
|
||||||
|
"menuColor": "メニューカラー",
|
||||||
|
"radius": "角丸",
|
||||||
|
"template": "テンプレート",
|
||||||
|
"createProject": "プロジェクトを作成"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"loading": "プレビューを読み込み中..."
|
||||||
|
},
|
||||||
|
"createDialog": {
|
||||||
|
"title": "プロジェクトを作成",
|
||||||
|
"projectName": "プロジェクト名",
|
||||||
|
"projectNamePlaceholder": "my-app",
|
||||||
|
"frameworkTemplate": "フレームワークテンプレート",
|
||||||
|
"packageManager": "パッケージマネージャー",
|
||||||
|
"saveDirectory": "保存先ディレクトリ",
|
||||||
|
"saveDirectoryPlaceholder": "ディレクトリを選択...",
|
||||||
|
"browseDirectory": "参照",
|
||||||
|
"cancel": "キャンセル",
|
||||||
|
"create": "作成",
|
||||||
|
"creating": "プロジェクトを作成中..."
|
||||||
|
},
|
||||||
|
"toasts": {
|
||||||
|
"createFailed": "プロジェクトの作成に失敗しました",
|
||||||
|
"createSuccess": "プロジェクトが正常に作成されました"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"directoryExists": "ディレクトリは既に存在し、空ではありません。",
|
||||||
|
"commandFailed": "プロジェクト作成コマンドが失敗しました。"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,15 @@
|
|||||||
"removeFromHistory": "기록에서 제거",
|
"removeFromHistory": "기록에서 제거",
|
||||||
"openFolder": "폴더 열기",
|
"openFolder": "폴더 열기",
|
||||||
"cloneRepository": "저장소 클론",
|
"cloneRepository": "저장소 클론",
|
||||||
|
"projectBoot": "프로젝트 부트",
|
||||||
"softwareVersion": "버전 {version}",
|
"softwareVersion": "버전 {version}",
|
||||||
"toasts": {
|
"toasts": {
|
||||||
"loadFolderHistoryFailed": "폴더 기록을 불러오지 못했습니다",
|
"loadFolderHistoryFailed": "폴더 기록을 불러오지 못했습니다",
|
||||||
"openFolderFailed": "폴더를 열지 못했습니다",
|
"openFolderFailed": "폴더를 열지 못했습니다",
|
||||||
"removeFromHistoryFailed": "기록에서 제거하지 못했습니다",
|
"removeFromHistoryFailed": "기록에서 제거하지 못했습니다",
|
||||||
"openSettingsFailed": "설정을 열지 못했습니다",
|
"openSettingsFailed": "설정을 열지 못했습니다",
|
||||||
"cloneFailed": "저장소 클론에 실패했습니다"
|
"cloneFailed": "저장소 클론에 실패했습니다",
|
||||||
|
"openProjectBootFailed": "프로젝트 부트를 열지 못했습니다"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"unknown": "예기치 않은 오류가 발생했습니다",
|
"unknown": "예기치 않은 오류가 발생했습니다",
|
||||||
@@ -1571,5 +1573,50 @@
|
|||||||
"loadingHunk": "Hunk 로딩 중...",
|
"loadingHunk": "Hunk 로딩 중...",
|
||||||
"noDiffData": "Diff 데이터 없음"
|
"noDiffData": "Diff 데이터 없음"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ProjectBoot": {
|
||||||
|
"title": "프로젝트 부트",
|
||||||
|
"tabs": {
|
||||||
|
"shadcn": "shadcn"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"base": "베이스",
|
||||||
|
"style": "스타일",
|
||||||
|
"baseColor": "베이스 색상",
|
||||||
|
"theme": "테마",
|
||||||
|
"chartColor": "차트 색상",
|
||||||
|
"iconLibrary": "아이콘 라이브러리",
|
||||||
|
"font": "글꼴",
|
||||||
|
"fontHeading": "제목 글꼴",
|
||||||
|
"menuAccent": "메뉴 강조",
|
||||||
|
"menuColor": "메뉴 색상",
|
||||||
|
"radius": "둥글기",
|
||||||
|
"template": "템플릿",
|
||||||
|
"createProject": "프로젝트 만들기"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"loading": "미리보기 로딩 중..."
|
||||||
|
},
|
||||||
|
"createDialog": {
|
||||||
|
"title": "프로젝트 만들기",
|
||||||
|
"projectName": "프로젝트 이름",
|
||||||
|
"projectNamePlaceholder": "my-app",
|
||||||
|
"frameworkTemplate": "프레임워크 템플릿",
|
||||||
|
"packageManager": "패키지 매니저",
|
||||||
|
"saveDirectory": "저장 디렉토리",
|
||||||
|
"saveDirectoryPlaceholder": "디렉토리 선택...",
|
||||||
|
"browseDirectory": "찾아보기",
|
||||||
|
"cancel": "취소",
|
||||||
|
"create": "만들기",
|
||||||
|
"creating": "프로젝트 생성 중..."
|
||||||
|
},
|
||||||
|
"toasts": {
|
||||||
|
"createFailed": "프로젝트 생성에 실패했습니다",
|
||||||
|
"createSuccess": "프로젝트가 성공적으로 생성되었습니다"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"directoryExists": "디렉토리가 이미 존재하며 비어 있지 않습니다.",
|
||||||
|
"commandFailed": "프로젝트 생성 명령이 실패했습니다."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,15 @@
|
|||||||
"removeFromHistory": "Remover do histórico",
|
"removeFromHistory": "Remover do histórico",
|
||||||
"openFolder": "Abrir pasta",
|
"openFolder": "Abrir pasta",
|
||||||
"cloneRepository": "Clonar repositório",
|
"cloneRepository": "Clonar repositório",
|
||||||
|
"projectBoot": "Inicializador de Projeto",
|
||||||
"softwareVersion": "versão {version}",
|
"softwareVersion": "versão {version}",
|
||||||
"toasts": {
|
"toasts": {
|
||||||
"loadFolderHistoryFailed": "Falha ao carregar o histórico de pastas",
|
"loadFolderHistoryFailed": "Falha ao carregar o histórico de pastas",
|
||||||
"openFolderFailed": "Falha ao abrir a pasta",
|
"openFolderFailed": "Falha ao abrir a pasta",
|
||||||
"removeFromHistoryFailed": "Falha ao remover a pasta",
|
"removeFromHistoryFailed": "Falha ao remover a pasta",
|
||||||
"openSettingsFailed": "Falha ao abrir as configurações",
|
"openSettingsFailed": "Falha ao abrir as configurações",
|
||||||
"cloneFailed": "Falha ao clonar o repositório"
|
"cloneFailed": "Falha ao clonar o repositório",
|
||||||
|
"openProjectBootFailed": "Falha ao abrir o inicializador de projeto"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"unknown": "Erro inesperado",
|
"unknown": "Erro inesperado",
|
||||||
@@ -1571,5 +1573,50 @@
|
|||||||
"loadingHunk": "Carregando hunk...",
|
"loadingHunk": "Carregando hunk...",
|
||||||
"noDiffData": "Sem dados de diff"
|
"noDiffData": "Sem dados de diff"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ProjectBoot": {
|
||||||
|
"title": "Inicializador de Projeto",
|
||||||
|
"tabs": {
|
||||||
|
"shadcn": "shadcn"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"base": "Base",
|
||||||
|
"style": "Estilo",
|
||||||
|
"baseColor": "Cor base",
|
||||||
|
"theme": "Tema",
|
||||||
|
"chartColor": "Cor do gráfico",
|
||||||
|
"iconLibrary": "Biblioteca de ícones",
|
||||||
|
"font": "Fonte",
|
||||||
|
"fontHeading": "Fonte do título",
|
||||||
|
"menuAccent": "Destaque do menu",
|
||||||
|
"menuColor": "Cor do menu",
|
||||||
|
"radius": "Raio",
|
||||||
|
"template": "Modelo",
|
||||||
|
"createProject": "Criar projeto"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"loading": "Carregando visualização..."
|
||||||
|
},
|
||||||
|
"createDialog": {
|
||||||
|
"title": "Criar projeto",
|
||||||
|
"projectName": "Nome do projeto",
|
||||||
|
"projectNamePlaceholder": "my-app",
|
||||||
|
"frameworkTemplate": "Modelo de framework",
|
||||||
|
"packageManager": "Gerenciador de pacotes",
|
||||||
|
"saveDirectory": "Diretório de salvamento",
|
||||||
|
"saveDirectoryPlaceholder": "Selecionar diretório...",
|
||||||
|
"browseDirectory": "Procurar",
|
||||||
|
"cancel": "Cancelar",
|
||||||
|
"create": "Criar",
|
||||||
|
"creating": "Criando projeto..."
|
||||||
|
},
|
||||||
|
"toasts": {
|
||||||
|
"createFailed": "Falha ao criar o projeto",
|
||||||
|
"createSuccess": "Projeto criado com sucesso"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"directoryExists": "O diretório já existe e não está vazio.",
|
||||||
|
"commandFailed": "O comando de criação do projeto falhou."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,15 @@
|
|||||||
"removeFromHistory": "从历史中移除",
|
"removeFromHistory": "从历史中移除",
|
||||||
"openFolder": "打开文件夹",
|
"openFolder": "打开文件夹",
|
||||||
"cloneRepository": "克隆仓库",
|
"cloneRepository": "克隆仓库",
|
||||||
|
"projectBoot": "项目启动器",
|
||||||
"softwareVersion": "版本 {version}",
|
"softwareVersion": "版本 {version}",
|
||||||
"toasts": {
|
"toasts": {
|
||||||
"loadFolderHistoryFailed": "加载文件夹历史失败",
|
"loadFolderHistoryFailed": "加载文件夹历史失败",
|
||||||
"openFolderFailed": "打开文件夹失败",
|
"openFolderFailed": "打开文件夹失败",
|
||||||
"removeFromHistoryFailed": "移除历史记录失败",
|
"removeFromHistoryFailed": "移除历史记录失败",
|
||||||
"openSettingsFailed": "打开设置失败",
|
"openSettingsFailed": "打开设置失败",
|
||||||
"cloneFailed": "克隆仓库失败"
|
"cloneFailed": "克隆仓库失败",
|
||||||
|
"openProjectBootFailed": "打开项目启动器失败"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"unknown": "发生未知错误",
|
"unknown": "发生未知错误",
|
||||||
@@ -1571,5 +1573,50 @@
|
|||||||
"loadingHunk": "正在加载代码块...",
|
"loadingHunk": "正在加载代码块...",
|
||||||
"noDiffData": "无差异数据"
|
"noDiffData": "无差异数据"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ProjectBoot": {
|
||||||
|
"title": "项目启动器",
|
||||||
|
"tabs": {
|
||||||
|
"shadcn": "shadcn"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"base": "基础库",
|
||||||
|
"style": "风格",
|
||||||
|
"baseColor": "基础颜色",
|
||||||
|
"theme": "主题",
|
||||||
|
"chartColor": "图表颜色",
|
||||||
|
"iconLibrary": "图标库",
|
||||||
|
"font": "字体",
|
||||||
|
"fontHeading": "标题字体",
|
||||||
|
"menuAccent": "菜单强调",
|
||||||
|
"menuColor": "菜单颜色",
|
||||||
|
"radius": "圆角",
|
||||||
|
"template": "模板",
|
||||||
|
"createProject": "创建项目"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"loading": "加载预览..."
|
||||||
|
},
|
||||||
|
"createDialog": {
|
||||||
|
"title": "创建项目",
|
||||||
|
"projectName": "项目名称",
|
||||||
|
"projectNamePlaceholder": "my-app",
|
||||||
|
"frameworkTemplate": "框架模板",
|
||||||
|
"packageManager": "包管理器",
|
||||||
|
"saveDirectory": "保存目录",
|
||||||
|
"saveDirectoryPlaceholder": "选择目录...",
|
||||||
|
"browseDirectory": "浏览",
|
||||||
|
"cancel": "取消",
|
||||||
|
"create": "创建",
|
||||||
|
"creating": "正在创建项目..."
|
||||||
|
},
|
||||||
|
"toasts": {
|
||||||
|
"createFailed": "创建项目失败",
|
||||||
|
"createSuccess": "项目创建成功"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"directoryExists": "目录已存在且不为空。",
|
||||||
|
"commandFailed": "项目创建命令执行失败。"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,15 @@
|
|||||||
"removeFromHistory": "從歷史中移除",
|
"removeFromHistory": "從歷史中移除",
|
||||||
"openFolder": "打開資料夾",
|
"openFolder": "打開資料夾",
|
||||||
"cloneRepository": "複製倉庫",
|
"cloneRepository": "複製倉庫",
|
||||||
|
"projectBoot": "專案啟動器",
|
||||||
"softwareVersion": "版本 {version}",
|
"softwareVersion": "版本 {version}",
|
||||||
"toasts": {
|
"toasts": {
|
||||||
"loadFolderHistoryFailed": "載入資料夾歷史失敗",
|
"loadFolderHistoryFailed": "載入資料夾歷史失敗",
|
||||||
"openFolderFailed": "打開資料夾失敗",
|
"openFolderFailed": "打開資料夾失敗",
|
||||||
"removeFromHistoryFailed": "移除歷史記錄失敗",
|
"removeFromHistoryFailed": "移除歷史記錄失敗",
|
||||||
"openSettingsFailed": "打開設定失敗",
|
"openSettingsFailed": "打開設定失敗",
|
||||||
"cloneFailed": "複製倉庫失敗"
|
"cloneFailed": "複製倉庫失敗",
|
||||||
|
"openProjectBootFailed": "開啟專案啟動器失敗"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"unknown": "發生未知錯誤",
|
"unknown": "發生未知錯誤",
|
||||||
@@ -1571,5 +1573,50 @@
|
|||||||
"loadingHunk": "正在載入區塊...",
|
"loadingHunk": "正在載入區塊...",
|
||||||
"noDiffData": "無差異資料"
|
"noDiffData": "無差異資料"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"ProjectBoot": {
|
||||||
|
"title": "專案啟動器",
|
||||||
|
"tabs": {
|
||||||
|
"shadcn": "shadcn"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"base": "基礎庫",
|
||||||
|
"style": "風格",
|
||||||
|
"baseColor": "基礎顏色",
|
||||||
|
"theme": "主題",
|
||||||
|
"chartColor": "圖表顏色",
|
||||||
|
"iconLibrary": "圖示庫",
|
||||||
|
"font": "字體",
|
||||||
|
"fontHeading": "標題字體",
|
||||||
|
"menuAccent": "選單強調",
|
||||||
|
"menuColor": "選單顏色",
|
||||||
|
"radius": "圓角",
|
||||||
|
"template": "模板",
|
||||||
|
"createProject": "建立專案"
|
||||||
|
},
|
||||||
|
"preview": {
|
||||||
|
"loading": "載入預覽..."
|
||||||
|
},
|
||||||
|
"createDialog": {
|
||||||
|
"title": "建立專案",
|
||||||
|
"projectName": "專案名稱",
|
||||||
|
"projectNamePlaceholder": "my-app",
|
||||||
|
"frameworkTemplate": "框架模板",
|
||||||
|
"packageManager": "套件管理器",
|
||||||
|
"saveDirectory": "儲存目錄",
|
||||||
|
"saveDirectoryPlaceholder": "選擇目錄...",
|
||||||
|
"browseDirectory": "瀏覽",
|
||||||
|
"cancel": "取消",
|
||||||
|
"create": "建立",
|
||||||
|
"creating": "正在建立專案..."
|
||||||
|
},
|
||||||
|
"toasts": {
|
||||||
|
"createFailed": "建立專案失敗",
|
||||||
|
"createSuccess": "專案建立成功"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"directoryExists": "目錄已存在且不為空。",
|
||||||
|
"commandFailed": "專案建立命令執行失敗。"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -951,6 +951,29 @@ export async function openSettingsWindow(
|
|||||||
window.open(result.path, `settings-${section ?? "general"}`)
|
window.open(result.path, `settings-${section ?? "general"}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function openProjectBootWindow(): Promise<void> {
|
||||||
|
if (getTransport().isDesktop()) {
|
||||||
|
return getTransport().call("open_project_boot_window")
|
||||||
|
}
|
||||||
|
window.open("/project-boot", "project-boot")
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function createShadcnProject(params: {
|
||||||
|
projectName: string
|
||||||
|
template: string
|
||||||
|
presetCode: string
|
||||||
|
packageManager: string
|
||||||
|
targetDir: string
|
||||||
|
}): Promise<string> {
|
||||||
|
return getTransport().call("create_shadcn_project", {
|
||||||
|
projectName: params.projectName,
|
||||||
|
template: params.template,
|
||||||
|
presetCode: params.presetCode,
|
||||||
|
packageManager: params.packageManager,
|
||||||
|
targetDir: params.targetDir,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export async function listOpenFolders(): Promise<FolderHistoryEntry[]> {
|
export async function listOpenFolders(): Promise<FolderHistoryEntry[]> {
|
||||||
return getTransport().call("list_open_folders")
|
return getTransport().call("list_open_folders")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user