Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathShellDocsOptions.cs
More file actions
Latest commit
178 lines (157 loc) · 6.65 KB
/
Copy pathShellDocsOptions.cs
File metadata and controls
178 lines (157 loc) · 6.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
usingSystem.Reflection;
usingMicrosoft.AspNetCore.Components;
usingShellDocs.Markdown;
namespaceShellDocs.Components;
publicclassShellDocsOptions
{
publicstringContentRoot{get;set;}="content";
publicstringSiteName{get;set;}="";
publicstring?SiteTagline{get;set;}
publicstring?GitHubRepo{get;set;}
publicstring?LogoLight{get;set;}
publicstring?LogoDark{get;set;}
publicstring?LogoAlt{get;set;}
publicdoubleLogoHeight{get;set;}=1.375;
// Rendered as MarkupString — must be trusted content the consumer authored, not user input.
publicstring?LogoSvg{get;set;}
publicShellDocsThemeTheme{get;set;}=ShellDocsTheme.Shadcn;
publicDocsLayoutVariantLayoutVariant{get;set;}=DocsLayoutVariant.TopNav;
publicList<NavLink>PrimaryNav{get;}=new();
// 0 or 1 entries hides the sidebar package selector entirely.
publicList<DocsPackage>Packages{get;}=new();
publicList<Type>RegisteredComponents{get;}=new();
/* Per-type tag alias — when a type appears here, BuildTypeRegistry uses this
string as the markdown-facing tag name instead of the type's short name.
Consumers use this to expose a component under a different name in docs
(e.g. RegisterComponent<Button>("Btn")). Last-write-wins if the same type
is registered under multiple aliases. */
publicDictionary<Type,string>ComponentAliases{get;}=new();
publicShellDocsOptionsRegisterComponent<T>()whereT:ComponentBase
{
RegisteredComponents.Add(typeof(T));
returnthis;
}
publicShellDocsOptionsRegisterComponent<T>(stringtagName)whereT:ComponentBase
{
if(string.IsNullOrWhiteSpace(tagName))
thrownewArgumentException("tagName must be non-empty.",nameof(tagName));
RegisteredComponents.Add(typeof(T));
ComponentAliases[typeof(T)]=tagName;
returnthis;
}
publicShellDocsOptionsRegisterComponent(Typetype)
{
if(!typeof(ComponentBase).IsAssignableFrom(type))
thrownewArgumentException($"{type.FullName} must derive from ComponentBase.",nameof(type));
RegisteredComponents.Add(type);
returnthis;
}
publicShellDocsOptionsRegisterComponent(Typetype,stringtagName)
{
if(!typeof(ComponentBase).IsAssignableFrom(type))
thrownewArgumentException($"{type.FullName} must derive from ComponentBase.",nameof(type));
if(string.IsNullOrWhiteSpace(tagName))
thrownewArgumentException("tagName must be non-empty.",nameof(tagName));
RegisteredComponents.Add(type);
ComponentAliases[type]=tagName;
returnthis;
}
/* Scan the assembly that TMarker lives in for all public, concrete,
non-generic ComponentBase-derived types and register each. Skips types
tagged with [ShellDocsIgnore]. Duplicate registrations against the same
tag name are silently ignored downstream in TypeRegistry. */
publicShellDocsOptionsRegisterComponentsFromAssembly<TMarker>(Func<Type,bool>?filter=null)
=>RegisterComponentsFromAssembly(typeof(TMarker).Assembly,filter);
publicShellDocsOptionsRegisterComponentsFromAssembly(Assemblyassembly,Func<Type,bool>?filter=null)
{
if(assemblyisnull)thrownewArgumentNullException(nameof(assembly));
foreach(vartypeinDiscoverComponentTypes(assembly))
{
if(filteris not null&&!filter(type))continue;
RegisteredComponents.Add(type);
}
returnthis;
}
privatestaticIEnumerable<Type>DiscoverComponentTypes(Assemblyassembly)
{
Type[]types;
try{types=assembly.GetTypes();}
catch(ReflectionTypeLoadExceptionex)
{
/* An assembly with a partially-loadable type surface still yields
its resolvable types via the exception's Types property (nulls
are the unresolvable ones). Salvage what we can. */
types=ex.Types.Where(t =>tis not null).ToArray()!;
}
foreach(vartintypes)
{
if(tisnull)continue;
if(!t.IsClass||t.IsAbstract)continue;
if(!t.IsPublic&&!t.IsNestedPublic)continue;
if(t.IsGenericTypeDefinition)continue;
if(!typeof(ComponentBase).IsAssignableFrom(t))continue;
if(t.IsDefined(typeof(ShellDocsIgnoreAttribute),inherit:false))continue;
yieldreturnt;
}
}
publicShellDocsOptionsAddNavLink(stringlabel,stringhref)
{
PrimaryNav.Add(newNavLink(label,href));
returnthis;
}
publicShellDocsOptionsAddNavMenu(stringlabel,paramsNavMenuItem[]items)
{
PrimaryNav.Add(newNavLink(label,"#",Children:items.ToList()));
returnthis;
}
publicShellDocsOptionsAddPackage(stringid,stringtitle,stringdescription,stringrootUrl,string?iconPath=null)
{
Packages.Add(newDocsPackage(id,title,description,rootUrl,iconPath));
returnthis;
}
publicShellDocsOptionsSetLogo(stringurl,string?alt=null)
{
LogoLight=url;
LogoDark=url;
if(altis not null)LogoAlt=alt;
returnthis;
}
publicShellDocsOptionsSetLogo(stringlightUrl,stringdarkUrl,string?alt=null)
{
LogoLight=lightUrl;
LogoDark=darkUrl;
if(altis not null)LogoAlt=alt;
returnthis;
}
internalTypeRegistryBuildTypeRegistry()
{
varregistry=newTypeRegistry();
foreach(vartypeinRegisteredComponents)
{
if(ComponentAliases.TryGetValue(type,outvaralias))
registry.Register(alias,type);
else
registry.Register(type);
}
returnregistry;
}
}
publicrecordNavLink(stringLabel,stringHref,List<NavMenuItem>?Children=null);
publicrecordNavMenuItem(stringLabel,stringHref,string?Description=null,string?IconSvg=null);
// IconPath is a raw SVG `d` attribute value on a 24×24 viewBox — not a URL.
publicrecordDocsPackage(stringId,stringTitle,stringDescription,stringRootUrl,string?IconPath=null);
publicenumShellDocsTheme
{
Shadcn,
Fuma,
Nextra
}
/* Which docs-layout chrome to render. TopNav is the classic build (DocsHeader
spanning the top + sidebar below). Sidebar drops the top nav and moves
brand + search + collapse into the sidebar itself — floating shadcn
sidebar-04 / Claude-Code aesthetic. */
publicenumDocsLayoutVariant
{
TopNav=0,
Sidebar=1
}