초기 커밋: SheetMe 서식생성기 (P0~P5 완료 상태)

레거시 서식생성기(VB.NET WinForms) 대체용 C#/.NET 10 WPF 디자이너.
기준선: 실DB 활성 디자인 1,271건 왕복 의미론 diff 0 / 예외 0, 단위 테스트 49/49.

이 커밋에 함께 포함된 자격증명 분리:
- appsettings.json 을 __HOST__/__PASSWORD__ 플레이스홀더로 전환
- 실접속 정보는 appsettings.Development.json 으로 분리(.gitignore 제외,
  csproj Debug 조건부 복사라 Release 산출물에 실리지 않음)
- ConfigLoader 를 환경변수 > Development > appsettings 순 레이어링으로 변경,
  미치환 플레이스홀더는 '미설정'으로 간주

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Msystech
2026-08-11 17:20:22 +09:00
co-authored by Claude Fable 5
commit 16c07f48dc
102 changed files with 14210 additions and 0 deletions
@@ -0,0 +1,102 @@
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace SheetMe.Designer.Controls;
/// <summary>
/// 팔레트 타입 → (Lucide 아이콘, 카테고리) 매핑 — [200]SheetMe 팔레트 타일 룩 이식.
/// Core(ControlRegistry)는 UI 무관하게 유지하고 표시 계층인 여기서만 매핑한다.
/// </summary>
public static class PaletteIconCatalog
{
#region Member Fields
private static readonly Dictionary<string, (string Icon, string Category)> Map = new(StringComparer.Ordinal)
{
["Label"] = ("type", "표시"),
["PictureBox"] = ("image", "표시"),
["Line"] = ("minus", "표시"),
["TextBox"] = ("text-cursor-input", "입력"),
["MaskedTextBox"] = ("text-cursor-input", "입력"),
["ComboBox"] = ("chevron-down", "입력"),
["ListBox"] = ("list", "입력"),
["CheckList"] = ("list-checks", "입력"),
["DateTimePicker"] = ("calendar", "입력"),
["CalcBox"] = ("sigma", "입력"),
["CheckBox"] = ("square-check", "선택"),
["RadioButton"] = ("circle-dot", "선택"),
["Panel"] = ("box", "컨테이너"),
["GroupBox"] = ("package", "컨테이너"),
["Button"] = ("mouse-pointer-click", "동작/데이터"),
["DataTable"] = ("table", "동작/데이터"),
};
#endregion
#region Methods
/// <summary>타입의 Lucide 아이콘명(미지정 타입은 square)</summary>
public static string IconOf(string type) => Map.TryGetValue(type, out var entry) ? entry.Icon : "square";
/// <summary>타입의 팔레트 카테고리(그룹 헤더)</summary>
public static string CategoryOf(string type) => Map.TryGetValue(type, out var entry) ? entry.Category : "기타";
#endregion
}
/// <summary>팔레트 타입명 → Lucide 아이콘 비주얼(FrameworkElement) 컨버터. parameter=크기(기본 18)</summary>
public sealed class TypeToIconConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is not string type)
{
return null;
}
var size = parameter is string s && double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var v) ? v : 18;
var brush = System.Windows.Application.Current.TryFindResource("B.Muted") as Brush ?? Brushes.Gray;
return LucideIcons.Icon(PaletteIconCatalog.IconOf(type), size, brush);
}
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
=> throw new NotSupportedException();
}
/// <summary>팔레트 타입명 → 카테고리명 컨버터(CollectionViewSource 그룹핑용)</summary>
public sealed class TypeToCategoryConverter : IValueConverter
{
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
=> value is string type ? PaletteIconCatalog.CategoryOf(type) : "기타";
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
=> throw new NotSupportedException();
}
/// <summary>불리언 반전 컨버터(선택 도구 토글 = !IsHandTool 표시용)</summary>
public sealed class InverseBoolConverter : IValueConverter
{
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
=> value is not true;
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
=> value is not true;
}
/// <summary>
/// Lucide 아이콘명 → 비주얼 컨버터(문서 탭 file-text, 플로팅 바 layout-grid 등 고정 아이콘용).
/// Binding Source 에 아이콘명 문자열을 넣어 사용 — 항목마다 새 비주얼이 생성되어 공유 부모 충돌이 없다.
/// parameter=크기(기본 14).
/// </summary>
public sealed class IconNameToVisualConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is not string name)
{
return null;
}
var size = parameter is string s && double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var v) ? v : 14;
var brush = System.Windows.Application.Current.TryFindResource("B.Muted") as Brush ?? Brushes.Gray;
return LucideIcons.Icon(name, size, brush);
}
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
=> throw new NotSupportedException();
}