embed readme

This commit is contained in:
2026-05-29 14:09:05 +08:00
parent 1ee22b7155
commit a2d80d2660
8 changed files with 248 additions and 81 deletions

View File

@@ -112,9 +112,14 @@ if ($Standalone) {
$exeName = "hpl-toolbox-$version.exe" $exeName = "hpl-toolbox-$version.exe"
$exeOut = Join-Path $distDir $exeName $exeOut = Join-Path $distDir $exeName
go build -ldflags="-s -w -H windowsgui -X main.AppVersion=$version" -trimpath -o $exeOut . $embeddedReadme = Join-Path (Get-Location) "README.md"
Copy-Item -Path (Join-Path $repoRoot "README.md") -Destination $embeddedReadme -Force
try {
go build -tags release -ldflags="-s -w -H windowsgui -X main.AppVersion=$version" -trimpath -o $exeOut .
if ($LASTEXITCODE -ne 0) { Write-Error "go build failed"; exit 1 } if ($LASTEXITCODE -ne 0) { Write-Error "go build failed"; exit 1 }
Copy-Item -Path (Join-Path $repoRoot "README.md") -Destination (Join-Path $distDir "README.md") -Force } finally {
Remove-Item -Path $embeddedReadme -Force -ErrorAction SilentlyContinue
}
$summary += [pscustomobject]@{ $summary += [pscustomobject]@{
Artifact = $exeName Artifact = $exeName

64
dist/README.md vendored
View File

@@ -1,64 +0,0 @@
# HPL Toolbox
Bundled VS Code extension and standalone tools for playable ad workflows.
# Changelog
**v0.1.2**
```
Added
- Added local hosting for HTML files.
- Added the standalone app.
```
**v0.1.3**
```
Added
- Added QR regeneration for AppLovin previews that fail to render.
- Added Save QR and Save All QRs actions.
Changed
- Updated AppLovin Demo Upload.
- Improved the file selection workflow.
```
**v0.1.5**
```
Added
- Added multi-file selection for PLEC Upload.
- Added automatic iteration name detection.
Changed
- Improved PLEC Upload file selection.
- Moved standalone temporary files into the user temp folder.
```
**v0.1.6**
```
Added
- Added beta tools for further testing:
- Playworks Converter for converting Playworks UnityAds HTML into other network variants.
- MRAID Checker for scanning HTML files against MRAID requirements and best practices.
Changed
- Simplified the UI.
```
**v0.1.7**
```
Added
- Added standalone drag-and-drop file/folder selection for HTML inputs across supported tools.
- Added status throbber/progress updates for batch scans, uploads, sharing, and conversions.
- Added streamed standalone progress updates so long-running actions update the status bar before completion.
Changed
- MRAID Checker is no longer marked as beta in extension or standalone.
- Playworks Converter source selection now matches the other file-selection UIs more closely.
- Playworks Converter default output folder now resolves to the input file location's Output folder.
- Progress text now follows the format: [throbber] Verb count file.
Fixed
- Fixed standalone drag-and-drop handling for multiple files and multiple folders.
- Fixed cleanup behavior for temporary dropped files when clearing or removing rows.
- Fixed standalone PLEC Upload Open button using an incorrect/mangled URL by switching to the Windows URL protocol handler.
```

Binary file not shown.

Binary file not shown.

View File

@@ -50,6 +50,14 @@ function getHtml(content: string): string {
font-size: 15px; font-size: 15px;
line-height: 1.3; line-height: 1.3;
} }
h3 {
margin: 14px 0 6px;
font-size: 13px;
line-height: 1.3;
}
strong {
font-weight: 600;
}
ul { ul {
margin: 6px 0 12px; margin: 6px 0 12px;
padding-left: 20px; padding-left: 20px;
@@ -62,6 +70,30 @@ function getHtml(content: string): string {
margin: 8px 0; margin: 8px 0;
line-height: 1.5; line-height: 1.5;
} }
code {
font-family: var(--vscode-editor-font-family, monospace);
font-size: 0.95em;
background: var(--vscode-textCodeBlock-background);
padding: 1px 4px;
border-radius: 3px;
}
.changelog-block {
margin: 8px 0 18px;
padding: 10px 12px;
border: 1px solid var(--vscode-panel-border);
border-radius: 4px;
background: var(--vscode-textCodeBlock-background);
}
.change-section {
margin: 8px 0 4px;
font-weight: 600;
}
.changelog-block ul {
margin: 4px 0 10px;
}
.changelog-block li.nested {
margin-left: 18px;
}
</style> </style>
</head> </head>
<body> <body>
@@ -74,6 +106,73 @@ function renderMarkdown(markdown: string): string {
const lines = markdown.replace(/\r\n/g, '\n').split('\n'); const lines = markdown.replace(/\r\n/g, '\n').split('\n');
const html: string[] = []; const html: string[] = [];
let inList = false; let inList = false;
let inCodeBlock = false;
let codeLines: string[] = [];
const closeList = () => {
if (inList) {
html.push('</ul>');
inList = false;
}
};
for (const rawLine of lines) {
if (rawLine.trim() === '```') {
closeList();
if (inCodeBlock) {
html.push(renderChangelogBlock(codeLines));
codeLines = [];
inCodeBlock = false;
} else {
inCodeBlock = true;
}
continue;
}
if (inCodeBlock) {
codeLines.push(rawLine);
continue;
}
const line = rawLine.trim();
if (!line) {
closeList();
continue;
}
const heading = line.match(/^(#{1,3})\s+(.+)$/);
if (heading) {
closeList();
const level = Math.min(heading[1].length, 2);
html.push(`<h${level}>${renderInlineMarkdown(heading[2])}</h${level}>`);
continue;
}
const boldHeading = line.match(/^\*\*(.+)\*\*$/);
if (boldHeading) {
closeList();
html.push(`<h2>${escapeHtml(boldHeading[1])}</h2>`);
continue;
}
const listItem = line.match(/^-\s+(.+)$/);
if (listItem) {
if (!inList) {
html.push('<ul>');
inList = true;
}
html.push(`<li>${renderInlineMarkdown(listItem[1])}</li>`);
continue;
}
closeList();
html.push(`<p>${renderInlineMarkdown(line)}</p>`);
}
if (inCodeBlock) {
html.push(renderChangelogBlock(codeLines));
}
closeList();
return html.join('\n');
}
function renderChangelogBlock(lines: string[]): string {
const html: string[] = ['<div class="changelog-block">'];
let inList = false;
const closeList = () => { const closeList = () => {
if (inList) { if (inList) {
@@ -88,29 +187,30 @@ function renderMarkdown(markdown: string): string {
closeList(); closeList();
continue; continue;
} }
const heading = line.match(/^(#{1,3})\s+(.+)$/);
if (heading) {
closeList();
const level = Math.min(heading[1].length, 2);
html.push(`<h${level}>${escapeHtml(heading[2])}</h${level}>`);
continue;
}
const listItem = line.match(/^-\s+(.+)$/); const listItem = line.match(/^-\s+(.+)$/);
if (listItem) { if (listItem) {
if (!inList) { if (!inList) {
html.push('<ul>'); html.push('<ul>');
inList = true; inList = true;
} }
html.push(`<li>${escapeHtml(listItem[1])}</li>`); const nested = rawLine.match(/^\s{8,}-\s+/) ? ' class="nested"' : '';
html.push(`<li${nested}>${renderInlineMarkdown(listItem[1])}</li>`);
continue; continue;
} }
closeList(); closeList();
html.push(`<p>${escapeHtml(line)}</p>`); html.push(`<div class="change-section">${renderInlineMarkdown(line)}</div>`);
} }
closeList(); closeList();
html.push('</div>');
return html.join('\n'); return html.join('\n');
} }
function renderInlineMarkdown(value: string): string {
return escapeHtml(value)
.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
.replace(/`([^`]+)`/g, '<code>$1</code>');
}
function escapeHtml(value: string): string { function escapeHtml(value: string): string {
return value.replace(/[&<>"']/g, ch => ({ return value.replace(/[&<>"']/g, ch => ({
'&': '&amp;', '&': '&amp;',

View File

@@ -24,9 +24,15 @@ func ChangelogPage(w http.ResponseWriter, r *http.Request) {
.changelog-panel { max-width: 840px; } .changelog-panel { max-width: 840px; }
.changelog-content h1 { margin: 0 0 14px; font-size: 20px; line-height: 1.25; } .changelog-content h1 { margin: 0 0 14px; font-size: 20px; line-height: 1.25; }
.changelog-content h2 { margin: 18px 0 8px; padding-top: 12px; border-top: 1px solid #333; font-size: 15px; line-height: 1.3; } .changelog-content h2 { margin: 18px 0 8px; padding-top: 12px; border-top: 1px solid #333; font-size: 15px; line-height: 1.3; }
.changelog-content h3 { margin: 14px 0 6px; font-size: 13px; line-height: 1.3; }
.changelog-content ul { margin: 6px 0 12px; padding-left: 20px; } .changelog-content ul { margin: 6px 0 12px; padding-left: 20px; }
.changelog-content li { margin: 4px 0; line-height: 1.45; } .changelog-content li { margin: 4px 0; line-height: 1.45; }
.changelog-content li.nested { margin-left: 18px; }
.changelog-content p { margin: 8px 0; line-height: 1.5; } .changelog-content p { margin: 8px 0; line-height: 1.5; }
.changelog-content code { font-family: Consolas, monospace; font-size: 0.95em; background: rgba(128,128,128,0.12); padding: 1px 4px; border-radius: 3px; }
.changelog-block { margin: 8px 0 18px; padding: 10px 12px; border: 1px solid #333; border-radius: 4px; background: rgba(128,128,128,0.08); }
.change-section { margin: 8px 0 4px; font-weight: 600; }
.changelog-block ul { margin: 4px 0 10px; }
</style>` </style>`
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
@@ -34,6 +40,9 @@ func ChangelogPage(w http.ResponseWriter, r *http.Request) {
} }
func readChangelog() string { func readChangelog() string {
if embeddedReadme != "" {
return embeddedReadme
}
for _, start := range changelogSearchRoots() { for _, start := range changelogSearchRoots() {
for _, candidate := range changelogCandidates(start) { for _, candidate := range changelogCandidates(start) {
data, err := os.ReadFile(candidate) data, err := os.ReadFile(candidate)
@@ -72,6 +81,8 @@ func renderChangelogMarkdown(markdown string) string {
lines := strings.Split(strings.ReplaceAll(markdown, "\r\n", "\n"), "\n") lines := strings.Split(strings.ReplaceAll(markdown, "\r\n", "\n"), "\n")
var out strings.Builder var out strings.Builder
inList := false inList := false
inCodeBlock := false
codeLines := []string{}
closeList := func() { closeList := func() {
if inList { if inList {
out.WriteString("</ul>") out.WriteString("</ul>")
@@ -80,6 +91,22 @@ func renderChangelogMarkdown(markdown string) string {
} }
for _, rawLine := range lines { for _, rawLine := range lines {
if strings.TrimSpace(rawLine) == "```" {
closeList()
if inCodeBlock {
out.WriteString(renderChangelogBlock(codeLines))
codeLines = []string{}
inCodeBlock = false
} else {
inCodeBlock = true
}
continue
}
if inCodeBlock {
codeLines = append(codeLines, rawLine)
continue
}
line := strings.TrimSpace(rawLine) line := strings.TrimSpace(rawLine)
if line == "" { if line == "" {
closeList() closeList()
@@ -87,17 +114,22 @@ func renderChangelogMarkdown(markdown string) string {
} }
if strings.HasPrefix(line, "### ") { if strings.HasPrefix(line, "### ") {
closeList() closeList()
out.WriteString("<h2>" + html.EscapeString(strings.TrimSpace(line[4:])) + "</h2>") out.WriteString("<h2>" + renderInlineMarkdown(strings.TrimSpace(line[4:])) + "</h2>")
continue continue
} }
if strings.HasPrefix(line, "## ") { if strings.HasPrefix(line, "## ") {
closeList() closeList()
out.WriteString("<h2>" + html.EscapeString(strings.TrimSpace(line[3:])) + "</h2>") out.WriteString("<h2>" + renderInlineMarkdown(strings.TrimSpace(line[3:])) + "</h2>")
continue continue
} }
if strings.HasPrefix(line, "# ") { if strings.HasPrefix(line, "# ") {
closeList() closeList()
out.WriteString("<h1>" + html.EscapeString(strings.TrimSpace(line[2:])) + "</h1>") out.WriteString("<h1>" + renderInlineMarkdown(strings.TrimSpace(line[2:])) + "</h1>")
continue
}
if strings.HasPrefix(line, "**") && strings.HasSuffix(line, "**") && len(line) > 4 {
closeList()
out.WriteString("<h2>" + html.EscapeString(strings.TrimSuffix(strings.TrimPrefix(line, "**"), "**")) + "</h2>")
continue continue
} }
if strings.HasPrefix(line, "- ") { if strings.HasPrefix(line, "- ") {
@@ -105,12 +137,93 @@ func renderChangelogMarkdown(markdown string) string {
out.WriteString("<ul>") out.WriteString("<ul>")
inList = true inList = true
} }
out.WriteString("<li>" + html.EscapeString(strings.TrimSpace(line[2:])) + "</li>") out.WriteString("<li>" + renderInlineMarkdown(strings.TrimSpace(line[2:])) + "</li>")
continue continue
} }
closeList() closeList()
out.WriteString("<p>" + html.EscapeString(line) + "</p>") out.WriteString("<p>" + renderInlineMarkdown(line) + "</p>")
}
if inCodeBlock {
out.WriteString(renderChangelogBlock(codeLines))
} }
closeList() closeList()
return out.String() return out.String()
} }
func renderChangelogBlock(lines []string) string {
var out strings.Builder
inList := false
closeList := func() {
if inList {
out.WriteString("</ul>")
inList = false
}
}
out.WriteString(`<div class="changelog-block">`)
for _, rawLine := range lines {
line := strings.TrimSpace(rawLine)
if line == "" {
closeList()
continue
}
if strings.HasPrefix(line, "- ") {
if !inList {
out.WriteString("<ul>")
inList = true
}
className := ""
if leadingSpaceCount(rawLine) >= 8 {
className = ` class="nested"`
}
out.WriteString("<li" + className + ">" + renderInlineMarkdown(strings.TrimSpace(line[2:])) + "</li>")
continue
}
closeList()
out.WriteString(`<div class="change-section">` + renderInlineMarkdown(line) + `</div>`)
}
closeList()
out.WriteString("</div>")
return out.String()
}
func renderInlineMarkdown(value string) string {
escaped := html.EscapeString(value)
escaped = replaceDelimited(escaped, "**", "strong")
escaped = replaceDelimited(escaped, "`", "code")
return escaped
}
func replaceDelimited(value, marker, tag string) string {
var out strings.Builder
for {
start := strings.Index(value, marker)
if start < 0 {
out.WriteString(value)
break
}
end := strings.Index(value[start+len(marker):], marker)
if end < 0 {
out.WriteString(value)
break
}
end += start + len(marker)
out.WriteString(value[:start])
out.WriteString("<" + tag + ">")
out.WriteString(value[start+len(marker) : end])
out.WriteString("</" + tag + ">")
value = value[end+len(marker):]
}
return out.String()
}
func leadingSpaceCount(value string) int {
count := 0
for _, ch := range value {
if ch != ' ' {
break
}
count++
}
return count
}

View File

@@ -0,0 +1,5 @@
//go:build !release
package main
const embeddedReadme = ""

View File

@@ -0,0 +1,8 @@
//go:build release
package main
import _ "embed"
//go:embed README.md
var embeddedReadme string