mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-08-11 20:32:11 +00:00
Fixed header template and added the app icon
This commit is contained in:
parent
d3e53fe5fe
commit
e567419566
@ -12,6 +12,11 @@ namespace AIStudio.Assistants.VisualBriefing;
|
||||
|
||||
public sealed partial class VisualBriefingArtifactService
|
||||
{
|
||||
/// <summary>
|
||||
/// Lazily loads the official MindWork AI Studio icon for self-contained exports.
|
||||
/// </summary>
|
||||
private static readonly Lazy<string> BRAND_ICON_DATA_URI = new(LoadBrandIconDataUri);
|
||||
|
||||
/// <summary>
|
||||
/// Assembles one self-contained briefing HTML file from validated parts.
|
||||
/// </summary>
|
||||
@ -79,10 +84,13 @@ public sealed partial class VisualBriefingArtifactService
|
||||
<meta name="referrer" content="no-referrer">
|
||||
<title>{HtmlEncode(briefingName)}</title>
|
||||
<style id="mwai-briefing-style">{css}</style>
|
||||
<style id="mwai-protected-style">{PROTECTED_FOOTER_CSS}</style>
|
||||
<style id="mwai-protected-style">{PROTECTED_STATIC_CSS}</style>
|
||||
</head>
|
||||
<body>
|
||||
<script id="{DATA_ELEMENT_ID}" type="application/json">{dataJson}</script>
|
||||
<header id="mwai-static-header">
|
||||
{BuildStaticHeaderTemplate()}
|
||||
</header>
|
||||
<div id="mwai-briefing-root">{template}</div>
|
||||
<footer id="mwai-static-footer" class="mwai-footer">
|
||||
{STATIC_FOOTER_TEMPLATE}
|
||||
@ -110,11 +118,39 @@ public sealed partial class VisualBriefingArtifactService
|
||||
[GeneratedRegex("""const AI_STUDIO_VERSION = (?<value>"(?:\\.|[^"\\])*");""", RegexOptions.CultureInvariant)]
|
||||
private static partial Regex RuntimeAIVersionRegex();
|
||||
|
||||
/// <summary>
|
||||
/// Builds the protected, app-owned static header template.
|
||||
/// </summary>
|
||||
private static string BuildStaticHeaderTemplate() => $"""
|
||||
<img src="{BRAND_ICON_DATA_URI.Value}" width="32" height="32" alt="" aria-hidden="true">
|
||||
<a href="{PROJECT_URL}" target="_blank" rel="noopener noreferrer">MINDWORK AI STUDIO</a>
|
||||
""";
|
||||
|
||||
/// <summary>
|
||||
/// Loads the official app icon as a Data URL so exported briefings remain self-contained.
|
||||
/// </summary>
|
||||
private static string LoadBrandIconDataUri()
|
||||
{
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
using var stream = assembly.GetManifestResourceStream("AIStudio.Assistants.VisualBriefing.Runtime.mindwork-ai-studio-icon.png") ??
|
||||
throw new InvalidOperationException("The official MindWork AI Studio icon is not available in this build.");
|
||||
|
||||
using var buffer = new MemoryStream();
|
||||
stream.CopyTo(buffer);
|
||||
|
||||
return $"data:image/png;base64,{Convert.ToBase64String(buffer.ToArray())}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Links exported MindWork AI Studio branding to the project repository.
|
||||
/// </summary>
|
||||
private const string PROJECT_URL = "https://github.com/MindWorkAI/AI-Studio";
|
||||
|
||||
/// <summary>
|
||||
/// Defines the protected, app-owned static footer template.
|
||||
/// </summary>
|
||||
private const string STATIC_FOOTER_TEMPLATE = """
|
||||
<span>Created with <a href="https://github.com/MindWorkAI/AI-Studio" target="_blank" rel="noopener noreferrer">MindWork AI Studio</a> v<span data-mwai-text="_mwai.aiStudioVersion"></span>.</span>
|
||||
private const string STATIC_FOOTER_TEMPLATE = $"""
|
||||
<span>Created with <a href="{PROJECT_URL}" target="_blank" rel="noopener noreferrer">MindWork AI Studio</a> v<span data-mwai-text="_mwai.aiStudioVersion"></span>.</span>
|
||||
<span data-mwai-text="_mwai.footer.models"></span>
|
||||
<span data-mwai-text="_mwai.footer.createdAt"></span>
|
||||
<span data-mwai-text="_mwai.footer.authors"></span>
|
||||
@ -122,9 +158,9 @@ public sealed partial class VisualBriefingArtifactService
|
||||
""";
|
||||
|
||||
/// <summary>
|
||||
/// Defines protected footer styles that model CSS cannot override.
|
||||
/// Defines protected static header and footer styles that model CSS cannot override.
|
||||
/// </summary>
|
||||
private const string PROTECTED_FOOTER_CSS = """
|
||||
private const string PROTECTED_STATIC_CSS = """
|
||||
html {
|
||||
background: #f3f6f3 !important;
|
||||
}
|
||||
@ -134,6 +170,50 @@ public sealed partial class VisualBriefingArtifactService
|
||||
background: #f3f6f3 !important;
|
||||
color: #172a24 !important;
|
||||
}
|
||||
#mwai-static-header {
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
gap: .75rem !important;
|
||||
position: relative !important;
|
||||
z-index: 2147483647 !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
max-width: 80rem !important;
|
||||
margin: 0 auto !important;
|
||||
padding: clamp(1rem, 3.5vw, 3rem) clamp(1rem, 3.5vw, 3rem) 0 !important;
|
||||
color: #164b3b !important;
|
||||
font: 700 .82rem/1.4 system-ui, sans-serif !important;
|
||||
letter-spacing: .08em !important;
|
||||
text-transform: uppercase !important;
|
||||
}
|
||||
#mwai-static-header img {
|
||||
box-sizing: border-box !important;
|
||||
display: block !important;
|
||||
flex: 0 0 auto !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
width: 2rem !important;
|
||||
height: 2rem !important;
|
||||
border-radius: .5rem !important;
|
||||
object-fit: cover !important;
|
||||
}
|
||||
#mwai-static-header a {
|
||||
display: inline !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
color: inherit !important;
|
||||
font: inherit !important;
|
||||
letter-spacing: inherit !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
#mwai-static-header a:hover {
|
||||
text-decoration: underline !important;
|
||||
text-underline-offset: .2em !important;
|
||||
}
|
||||
#mwai-static-header a:focus-visible {
|
||||
outline: 3px solid #f2d264 !important;
|
||||
outline-offset: 3px !important;
|
||||
}
|
||||
#mwai-static-footer {
|
||||
display: flex !important;
|
||||
flex-wrap: wrap !important;
|
||||
@ -163,10 +243,19 @@ public sealed partial class VisualBriefingArtifactService
|
||||
text-decoration: underline !important;
|
||||
text-underline-offset: .15em !important;
|
||||
}
|
||||
@media (max-width: 47.99rem) {
|
||||
#mwai-static-header {
|
||||
padding: .75rem .75rem 0 !important;
|
||||
}
|
||||
}
|
||||
@media print {
|
||||
html, body {
|
||||
background: #fffefa !important;
|
||||
}
|
||||
#mwai-static-header {
|
||||
max-width: none !important;
|
||||
padding: 0 0 12mm !important;
|
||||
}
|
||||
#mwai-static-footer {
|
||||
max-width: none !important;
|
||||
margin-top: 6mm !important;
|
||||
|
||||
@ -118,6 +118,7 @@ public sealed partial class VisualBriefingArtifactService
|
||||
var dataNode = FindUniqueElementById(document, DATA_ELEMENT_ID);
|
||||
var rootNode = FindUniqueElementById(document, "mwai-briefing-root");
|
||||
var footerNode = FindUniqueElementById(document, "mwai-static-footer");
|
||||
var headerNodes = FindNodes(document.DocumentNode, "//*[@id='mwai-static-header']")?.ToArray() ?? [];
|
||||
var generatedStyleNode = FindUniqueElementById(document, "mwai-briefing-style");
|
||||
var protectedStyleNode = FindUniqueElementById(document, "mwai-protected-style");
|
||||
var runtimeNode = FindUniqueElementById(document, "mwai-briefing-runtime");
|
||||
@ -128,6 +129,9 @@ public sealed partial class VisualBriefingArtifactService
|
||||
|
||||
if (htmlNode is null || headNode is null || bodyNode is null || dataNode is null || rootNode is null ||
|
||||
footerNode is null || generatedStyleNode is null || protectedStyleNode is null || runtimeNode is null ||
|
||||
headerNodes.Length > 1 ||
|
||||
(headerNodes.Length == 1 &&
|
||||
(!headerNodes[0].Name.Equals("header", StringComparison.OrdinalIgnoreCase) || headerNodes[0].ParentNode != bodyNode)) ||
|
||||
!styleMatch.Success || !runtimeMatch.Success || (echartsNode is not null) != echartsMatch.Success)
|
||||
{
|
||||
issue = "The briefing envelope is incomplete or ambiguous.";
|
||||
@ -153,6 +157,7 @@ public sealed partial class VisualBriefingArtifactService
|
||||
var allowedBodyIds = new HashSet<string>(StringComparer.Ordinal)
|
||||
{
|
||||
DATA_ELEMENT_ID,
|
||||
"mwai-static-header",
|
||||
"mwai-briefing-root",
|
||||
"mwai-static-footer",
|
||||
"mwai-echarts-runtime",
|
||||
|
||||
@ -120,10 +120,7 @@ internal sealed class VisualBriefingLayoutCompiler
|
||||
var layoutClasses = CompileLayoutClasses(node, $"mwai-layout mwai-{kind}");
|
||||
|
||||
if (isRoot)
|
||||
{
|
||||
var masthead = "<header class=\"mwai-masthead\"><div class=\"mwai-brand-mark\" aria-hidden=\"true\"><span></span><span></span><span></span><i></i></div><strong data-mwai-text=\"labels.brand\"></strong></header>";
|
||||
return $"<main id=\"{id}\" class=\"{layoutClasses} mwai-document\">{masthead}{children}</main>";
|
||||
}
|
||||
return $"<main id=\"{id}\" class=\"{layoutClasses} mwai-document\">{children}</main>";
|
||||
|
||||
return $"<div id=\"{id}\" class=\"{layoutClasses}\">{children}</div>";
|
||||
}
|
||||
@ -248,13 +245,9 @@ internal sealed class VisualBriefingLayoutCompiler
|
||||
};
|
||||
|
||||
var css = new StringBuilder($$"""
|
||||
#mwai-briefing-root{--mwai-ink:#172A24;--mwai-forest:#164B3B;--mwai-pine:#236A50;--mwai-sage:#79AE90;--mwai-cream:#F7F1DC;--mwai-paper:#FFFEFA;--mwai-sun:#F2D264;--mwai-mist:#EAF1EC;--mwai-clay:#C97857;--mwai-line:#D6E2DC;--mwai-muted:#5E7169;--mwai-type-scale:{{typeScale}};--mwai-rhythm:{{rhythm}};--mwai-section-space:{{sectionSpace}};max-width:80rem;margin-inline:auto;padding:clamp(1rem,3.5vw,3rem);font:calc(1rem*var(--mwai-type-scale))/1.65 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;color:var(--mwai-ink);}
|
||||
#mwai-briefing-root{--mwai-ink:#172A24;--mwai-forest:#164B3B;--mwai-pine:#236A50;--mwai-sage:#79AE90;--mwai-cream:#F7F1DC;--mwai-paper:#FFFEFA;--mwai-sun:#F2D264;--mwai-mist:#EAF1EC;--mwai-clay:#C97857;--mwai-line:#D6E2DC;--mwai-muted:#5E7169;--mwai-type-scale:{{typeScale}};--mwai-rhythm:{{rhythm}};--mwai-section-space:{{sectionSpace}};max-width:80rem;margin-inline:auto;padding:clamp(1rem,2.5vw,2rem) clamp(1rem,3.5vw,3rem) clamp(1rem,3.5vw,3rem);font:calc(1rem*var(--mwai-type-scale))/1.65 system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;color:var(--mwai-ink);}
|
||||
#mwai-briefing-root *{box-sizing:border-box;}
|
||||
.mwai-document{display:flex;flex-direction:column;gap:clamp(1rem,2.5vw,2rem);}
|
||||
.mwai-masthead{display:flex;align-items:center;gap:.75rem;padding:.35rem .25rem;color:var(--mwai-forest);font-size:.82rem;letter-spacing:.08em;text-transform:uppercase;}
|
||||
.mwai-brand-mark{position:relative;display:flex;align-items:center;gap:3px;width:2rem;height:1.55rem;padding-inline:.42rem;border-radius:.55rem;background:var(--mwai-cream);border:1px solid color-mix(in srgb,var(--mwai-pine),transparent 70%);}
|
||||
.mwai-brand-mark span{display:block;width:4px;height:4px;border-radius:50%;background:var(--mwai-pine);}
|
||||
.mwai-brand-mark i{position:absolute;left:.35rem;bottom:-.22rem;width:.45rem;height:.45rem;background:var(--mwai-cream);border-inline-start:1px solid color-mix(in srgb,var(--mwai-pine),transparent 70%);transform:skewY(-35deg);}
|
||||
.mwai-section{display:block;border-radius:clamp(1.25rem,2.5vw,2rem);}
|
||||
.mwai-section-inner{padding:clamp(2rem,5vw,var(--mwai-section-space));}
|
||||
.mwai-section-heading{max-width:52rem;margin-block-end:clamp(1.75rem,4vw,3.25rem);}
|
||||
@ -356,8 +349,8 @@ internal sealed class VisualBriefingLayoutCompiler
|
||||
|
||||
css.Append("""
|
||||
@media screen and (min-width:48rem){.mwai-timeline-horizontal .mwai-timeline-track{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(13rem,1fr);overflow-x:auto;padding:.55rem 0 .5rem;padding-inline-start:.55rem}.mwai-timeline-horizontal .mwai-timeline-item{padding:0;padding-block-start:1.5rem;padding-inline-end:1rem;border-block-start:2px solid var(--mwai-line);border-inline-start:0}.mwai-timeline-horizontal .mwai-timeline-marker{inset-block-start:-.52rem;inset-inline-start:-.52rem}}
|
||||
@media(max-width:47.99rem){#mwai-briefing-root{padding:.75rem}.mwai-section-inner{padding:1.5rem}.mwai-section-hero .mwai-section-inner{min-height:34rem}.mwai-metric,.mwai-chart,.mwai-asset,.mwai-table,.mwai-filterable_table,.mwai-tabs,.mwai-accordion,.mwai-simulation,.mwai-timeline{padding:1rem}[data-mwai-chart]{min-height:19rem}th,td{padding:.7rem .75rem}}
|
||||
@media print{@page{margin:14mm}#mwai-briefing-root{max-width:none;padding:0;font-size:10pt}.mwai-document{gap:8mm}.mwai-masthead{padding:0 0 4mm}.mwai-section{border:0;box-shadow:none;background:transparent;color:var(--mwai-ink);break-inside:auto}.mwai-section-inner{padding:6mm 0}.mwai-section-heading{margin-block-end:5mm}.mwai-section-heading h1{font-size:28pt}.mwai-section-heading h2{font-size:21pt}.mwai-section-heading p,.mwai-section-hero .mwai-section-heading p,.mwai-section-conclusion .mwai-section-heading p{color:var(--mwai-muted)}.mwai-component,.mwai-component figure,.mwai-table-wrap{break-inside:avoid}.mwai-timeline{break-inside:auto}.mwai-timeline-item{break-inside:avoid}.mwai-metric,.mwai-chart,.mwai-asset,.mwai-table,.mwai-filterable_table,.mwai-tabs,.mwai-accordion,.mwai-simulation,.mwai-timeline{box-shadow:none;background:var(--mwai-paper)}[data-mwai-tab-panel][hidden]{display:block!important}details:not([open])>.mwai-accordion-body{display:block!important}[data-mwai-reset]{display:none!important}thead th{position:static}*{print-color-adjust:exact}}
|
||||
@media(max-width:47.99rem){#mwai-briefing-root{padding:1rem .75rem .75rem}.mwai-section-inner{padding:1.5rem}.mwai-section-hero .mwai-section-inner{min-height:34rem}.mwai-metric,.mwai-chart,.mwai-asset,.mwai-table,.mwai-filterable_table,.mwai-tabs,.mwai-accordion,.mwai-simulation,.mwai-timeline{padding:1rem}[data-mwai-chart]{min-height:19rem}th,td{padding:.7rem .75rem}}
|
||||
@media print{@page{margin:14mm}#mwai-briefing-root{max-width:none;padding:0;font-size:10pt}.mwai-document{gap:8mm}.mwai-section{border:0;box-shadow:none;background:transparent;color:var(--mwai-ink);break-inside:auto}.mwai-section-inner{padding:6mm 0}.mwai-section-heading{margin-block-end:5mm}.mwai-section-heading h1{font-size:28pt}.mwai-section-heading h2{font-size:21pt}.mwai-section-heading p,.mwai-section-hero .mwai-section-heading p,.mwai-section-conclusion .mwai-section-heading p{color:var(--mwai-muted)}.mwai-component,.mwai-component figure,.mwai-table-wrap{break-inside:avoid}.mwai-timeline{break-inside:auto}.mwai-timeline-item{break-inside:avoid}.mwai-metric,.mwai-chart,.mwai-asset,.mwai-table,.mwai-filterable_table,.mwai-tabs,.mwai-accordion,.mwai-simulation,.mwai-timeline{box-shadow:none;background:var(--mwai-paper)}[data-mwai-tab-panel][hidden]{display:block!important}details:not([open])>.mwai-accordion-body{display:block!important}[data-mwai-reset]{display:none!important}thead th{position:static}*{print-color-adjust:exact}}
|
||||
""");
|
||||
|
||||
return css.ToString();
|
||||
|
||||
@ -18,7 +18,7 @@ public static class VisualBriefingVersions
|
||||
/// Gets the deterministic HTML, CSS, chart, and interaction compiler version. Increment this
|
||||
/// whenever compiler behavior changes so interrupted recompiles cannot resume across versions.
|
||||
/// </summary>
|
||||
public const int COMPILER = 2;
|
||||
public const int COMPILER = 3;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the embedded AI Studio runtime bundle version. Increment this for changes to the
|
||||
|
||||
@ -47,6 +47,7 @@
|
||||
<EmbeddedResource Include="Assistants\PromptOptimizer\prompting_guideline.md" CopyToOutputDirectory="PreserveNewest" />
|
||||
<EmbeddedResource Include="Assistants\Builder\AssistantBuilderLuaResponse.schema.json" CopyToOutputDirectory="PreserveNewest" />
|
||||
<EmbeddedResource Include="Assistants\VisualBriefing\Runtime\echarts.common.min.js" CopyToOutputDirectory="PreserveNewest" />
|
||||
<EmbeddedResource Include="..\..\runtime\icons\128x128.png" LogicalName="AIStudio.Assistants.VisualBriefing.Runtime.mindwork-ai-studio-icon.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user