Initial commit to new repository

This commit is contained in:
2026-04-03 18:22:19 +09:00
commit 4458bb0f52
7672 changed files with 452440 additions and 0 deletions

View File

@@ -0,0 +1,283 @@
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
namespace AxCopilot.Views;
/// <summary>커스텀 디자인 무드 추가/편집 다이얼로그.</summary>
internal sealed partial class CustomMoodDialog : Window
{
private readonly TextBox _keyBox;
private readonly TextBox _labelBox;
private readonly TextBox _iconBox;
private readonly TextBox _descBox;
private readonly TextBox _cssBox;
private readonly bool _isEdit;
public string MoodKey => _keyBox.Text.Trim().ToLowerInvariant();
public string MoodLabel => _labelBox.Text.Trim();
public string MoodIcon => _iconBox.Text.Trim();
public string MoodDescription => _descBox.Text.Trim();
public string MoodCss => _cssBox.Text;
public CustomMoodDialog(
string existingKey = "",
string existingLabel = "",
string existingIcon = "🎯",
string existingDesc = "",
string existingCss = "")
{
_isEdit = !string.IsNullOrEmpty(existingKey);
Title = _isEdit ? "무드 편집" : "무드 추가";
Width = 560;
SizeToContent = SizeToContent.Height;
WindowStartupLocation = WindowStartupLocation.CenterOwner;
ResizeMode = ResizeMode.NoResize;
WindowStyle = WindowStyle.None;
AllowsTransparency = true;
Background = Brushes.Transparent;
var bgBrush = Application.Current.TryFindResource("LauncherBackground") as Brush
?? new SolidColorBrush(Color.FromRgb(0x1A, 0x1B, 0x2E));
var primaryText = Application.Current.TryFindResource("PrimaryText") as Brush ?? Brushes.White;
var secondaryText = Application.Current.TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
var accentBrush = Application.Current.TryFindResource("AccentColor") as Brush ?? Brushes.Blue;
var itemBg = Application.Current.TryFindResource("ItemBackground") as Brush
?? new SolidColorBrush(Color.FromRgb(0x2A, 0x2B, 0x40));
var borderBrush = Application.Current.TryFindResource("BorderColor") as Brush ?? Brushes.Gray;
var root = new Border
{
Background = bgBrush,
CornerRadius = new CornerRadius(16),
BorderBrush = borderBrush,
BorderThickness = new Thickness(1),
Padding = new Thickness(28, 24, 28, 24),
Effect = new System.Windows.Media.Effects.DropShadowEffect
{
BlurRadius = 24, ShadowDepth = 4, Opacity = 0.3, Color = Colors.Black,
},
};
var stack = new StackPanel();
// 헤더
var header = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 0, 0, 20) };
header.Children.Add(new TextBlock
{
Text = "\uE771",
FontFamily = new FontFamily("Segoe MDL2 Assets"),
FontSize = 18, Foreground = accentBrush,
VerticalAlignment = VerticalAlignment.Center,
Margin = new Thickness(0, 0, 10, 0),
});
header.Children.Add(new TextBlock
{
Text = _isEdit ? "디자인 무드 편집" : "새 커스텀 디자인 무드",
FontSize = 17, FontWeight = FontWeights.Bold,
Foreground = primaryText, VerticalAlignment = VerticalAlignment.Center,
});
stack.Children.Add(header);
// ── 키 + 라벨 + 아이콘 (한 줄) ──
var row1 = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 0, 0, 8) };
// 키
var keyStack = new StackPanel { Margin = new Thickness(0, 0, 12, 0) };
AddLabel(keyStack, "키 (영문)", primaryText);
_keyBox = CreateTextBox(existingKey, primaryText, itemBg, accentBrush, borderBrush);
_keyBox.Width = 140;
_keyBox.IsEnabled = !_isEdit; // 편집 시 키 변경 불가
keyStack.Children.Add(new Border { CornerRadius = new CornerRadius(8), ClipToBounds = true, Child = _keyBox });
row1.Children.Add(keyStack);
// 라벨
var labelStack = new StackPanel { Margin = new Thickness(0, 0, 12, 0) };
AddLabel(labelStack, "이름", primaryText);
_labelBox = CreateTextBox(existingLabel, primaryText, itemBg, accentBrush, borderBrush);
_labelBox.Width = 180;
labelStack.Children.Add(new Border { CornerRadius = new CornerRadius(8), ClipToBounds = true, Child = _labelBox });
row1.Children.Add(labelStack);
// 아이콘 (이모지)
var iconStack = new StackPanel();
AddLabel(iconStack, "아이콘", primaryText);
_iconBox = CreateTextBox(existingIcon, primaryText, itemBg, accentBrush, borderBrush);
_iconBox.Width = 60;
_iconBox.TextAlignment = TextAlignment.Center;
iconStack.Children.Add(new Border { CornerRadius = new CornerRadius(8), ClipToBounds = true, Child = _iconBox });
row1.Children.Add(iconStack);
stack.Children.Add(row1);
// ── 설명 ──
AddLabel(stack, "설명", primaryText);
_descBox = CreateTextBox(existingDesc, primaryText, itemBg, accentBrush, borderBrush);
stack.Children.Add(new Border { CornerRadius = new CornerRadius(8), ClipToBounds = true, Child = _descBox, Margin = new Thickness(0, 0, 0, 8) });
// ── CSS ──
AddSeparator(stack, borderBrush);
AddLabel(stack, "CSS 스타일", primaryText);
AddHint(stack, "문서에 적용될 CSS입니다. body, h1~h6, table, .callout 등의 스타일을 정의하세요.", secondaryText);
_cssBox = CreateTextBox(existingCss, primaryText, itemBg, accentBrush, borderBrush, multiline: true, height: 200);
_cssBox.FontFamily = new FontFamily("Consolas, Courier New, monospace");
_cssBox.FontSize = 12;
stack.Children.Add(new Border { CornerRadius = new CornerRadius(8), ClipToBounds = true, Child = _cssBox });
// CSS 힌트 버튼
var hintBtn = new TextBlock
{
Text = "CSS 예시 보기",
FontSize = 11,
Foreground = accentBrush,
Cursor = Cursors.Hand,
Margin = new Thickness(0, 6, 0, 0),
TextDecorations = TextDecorations.Underline,
};
hintBtn.MouseLeftButtonDown += (_, _) =>
{
if (string.IsNullOrWhiteSpace(_cssBox.Text))
{
_cssBox.Text = CssExample;
}
};
stack.Children.Add(hintBtn);
// ── 버튼 바 ──
var btnBar = new StackPanel
{
Orientation = Orientation.Horizontal,
HorizontalAlignment = HorizontalAlignment.Right,
Margin = new Thickness(0, 20, 0, 0),
};
var cancelBtn = new Button
{
Content = "취소", Width = 80,
Padding = new Thickness(0, 8, 0, 8),
Margin = new Thickness(0, 0, 10, 0),
Background = Brushes.Transparent, Foreground = secondaryText,
BorderBrush = borderBrush, BorderThickness = new Thickness(1),
Cursor = Cursors.Hand, FontSize = 13,
};
cancelBtn.Click += (_, _) => { DialogResult = false; Close(); };
btnBar.Children.Add(cancelBtn);
var okBtn = new Button
{
Content = _isEdit ? "저장" : "추가", Width = 80,
Padding = new Thickness(0, 8, 0, 8),
Background = accentBrush, Foreground = Brushes.White,
BorderThickness = new Thickness(0),
Cursor = Cursors.Hand, FontSize = 13, FontWeight = FontWeights.SemiBold,
};
okBtn.Click += (_, _) => Validate();
btnBar.Children.Add(okBtn);
stack.Children.Add(btnBar);
root.Child = stack;
Content = root;
KeyDown += (_, ke) => { if (ke.Key == Key.Escape) { DialogResult = false; Close(); } };
Loaded += (_, _) => { (_isEdit ? _labelBox : _keyBox).Focus(); };
root.MouseLeftButtonDown += (_, me) =>
{
if (me.LeftButton == MouseButtonState.Pressed)
try { DragMove(); } catch { }
};
}
private void Validate()
{
if (string.IsNullOrWhiteSpace(_keyBox.Text))
{
CustomMessageBox.Show("키를 입력하세요 (영문 소문자).", "입력 오류", MessageBoxButton.OK, MessageBoxImage.Warning);
_keyBox.Focus(); return;
}
if (!Regex.IsMatch(_keyBox.Text.Trim(), @"^[a-z][a-z0-9_]{1,20}$"))
{
CustomMessageBox.Show("키는 영문 소문자로 시작하며, 소문자/숫자/밑줄만 허용됩니다 (2~21자).", "입력 오류", MessageBoxButton.OK, MessageBoxImage.Warning);
_keyBox.Focus(); return;
}
if (string.IsNullOrWhiteSpace(_labelBox.Text))
{
CustomMessageBox.Show("이름을 입력하세요.", "입력 오류", MessageBoxButton.OK, MessageBoxImage.Warning);
_labelBox.Focus(); return;
}
// 내장 무드 키와 충돌 확인
if (!_isEdit)
{
var builtinKeys = new[] { "modern", "professional", "creative", "minimal", "elegant", "dark", "colorful", "corporate", "magazine", "dashboard" };
if (builtinKeys.Contains(_keyBox.Text.Trim().ToLowerInvariant()))
{
CustomMessageBox.Show("내장 무드와 동일한 키는 사용할 수 없습니다.", "입력 오류", MessageBoxButton.OK, MessageBoxImage.Warning);
_keyBox.Focus(); return;
}
}
DialogResult = true;
Close();
}
private static void AddLabel(StackPanel parent, string text, Brush fg) =>
parent.Children.Add(new TextBlock
{
Text = text, FontSize = 12, FontWeight = FontWeights.SemiBold,
Foreground = fg, Margin = new Thickness(0, 0, 0, 6),
});
private static void AddHint(StackPanel parent, string text, Brush fg) =>
parent.Children.Add(new TextBlock
{
Text = text, FontSize = 11, Foreground = fg,
Margin = new Thickness(0, 0, 0, 8),
});
private static void AddSeparator(StackPanel parent, Brush color) =>
parent.Children.Add(new Rectangle
{
Height = 1, Fill = color,
Margin = new Thickness(0, 8, 0, 12), Opacity = 0.5,
});
private static TextBox CreateTextBox(string text, Brush fg, Brush bg, Brush caret, Brush border, bool multiline = false, int height = 100)
{
var tb = new TextBox
{
Text = text, FontSize = 13,
Padding = new Thickness(12, 8, 12, 8),
Foreground = fg, Background = bg,
CaretBrush = caret, BorderBrush = border,
BorderThickness = new Thickness(1),
};
if (multiline)
{
tb.AcceptsReturn = true;
tb.AcceptsTab = true;
tb.TextWrapping = TextWrapping.Wrap;
tb.MinHeight = height;
tb.MaxHeight = height + 100;
tb.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
}
return tb;
}
private const string CssExample = @"body {
font-family: 'Pretendard', 'Noto Sans KR', sans-serif;
max-width: 900px;
margin: 0 auto;
padding: 40px;
color: #1a1a2e;
background: #f8f9fc;
line-height: 1.8;
}
h1 { color: #2d3748; border-bottom: 2px solid #4a90d9; padding-bottom: 8px; }
h2 { color: #4a5568; margin-top: 2em; }
table { width: 100%; border-collapse: collapse; margin: 1.5em 0; }
th { background: #4a90d9; color: white; padding: 10px; text-align: left; }
td { padding: 8px 10px; border-bottom: 1px solid #e2e8f0; }
tr:nth-child(even) { background: #f0f4f8; }
";
}