diff --git a/dist/hpl-toolbox-0.1.6.exe b/dist/hpl-toolbox-0.1.6.exe index 47293ee..ce7cd40 100644 Binary files a/dist/hpl-toolbox-0.1.6.exe and b/dist/hpl-toolbox-0.1.6.exe differ diff --git a/dist/hpl-toolbox-0.1.6.vsix b/dist/hpl-toolbox-0.1.6.vsix index 417596c..0a579f6 100644 Binary files a/dist/hpl-toolbox-0.1.6.vsix and b/dist/hpl-toolbox-0.1.6.vsix differ diff --git a/src/launcherView.ts b/src/launcherView.ts index 66fd6e1..bb77429 100644 --- a/src/launcherView.ts +++ b/src/launcherView.ts @@ -65,7 +65,6 @@ export class LauncherViewProvider implements vscode.WebviewViewProvider { function getHtml(version: string, betaToolsEnabled: boolean): string { const visibleTools = sortToolsForDisplay(TOOLS.filter(tool => betaToolsEnabled || !tool.beta)); - const hiddenBetaCount = TOOLS.filter(tool => tool.beta).length - visibleTools.filter(tool => tool.beta).length; const toolButtons = visibleTools.map(renderToolButton).join('\n'); return ` @@ -140,38 +139,35 @@ function getHtml(version: string, betaToolsEnabled: boolean): string { font-size: 10px; text-transform: uppercase; } - .beta-toggle { - margin-top: 12px; + .footer { + margin-top: auto; padding-top: 8px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + color: var(--vscode-descriptionForeground); + font-size: 8px; border-top: 1px solid var(--vscode-panel-border); } - .beta-toggle button { - width: 100%; - padding: 7px 9px; + .beta-toggle { + padding: 0; background: transparent; - color: var(--vscode-foreground); - border: 1px solid var(--vscode-panel-border); - border-radius: 5px; + color: var(--vscode-descriptionForeground); + border: 0; cursor: pointer; text-align: left; font: inherit; - } - .beta-toggle button:hover { - background: var(--vscode-list-hoverBackground, var(--vscode-button-secondaryHoverBackground)); - } - .beta-note { - display: block; - margin-top: 3px; - color: var(--vscode-descriptionForeground); font-size: 10px; - line-height: 1.3; + opacity: 0.72; } - .footer { - margin-top: 8px; - color: var(--vscode-descriptionForeground); - font-size: 8px; - text-align: right; + .beta-toggle:hover { + opacity: 1; + text-decoration: underline; + } + .footer-version { opacity: 0.75; + text-align: right; } @@ -179,13 +175,10 @@ function getHtml(version: string, betaToolsEnabled: boolean): string {
${toolButtons}
-
- + - ` w.Header().Set("Content-Type", "text/html; charset=utf-8") - _, _ = w.Write([]byte(Page("/applovin", "AppLovin Upload", body))) + _, _ = w.Write([]byte(Page("/applovin", "AppLovin Playable Preview", body))) } func ApplovinPick(w http.ResponseWriter, r *http.Request) { @@ -253,6 +323,23 @@ func ApplovinPick(w http.ResponseWriter, r *http.Request) { writeJSON(w, map[string]any{"files": files}) } +func ApplovinPickFolder(w http.ResponseWriter, r *http.Request) { + cfg := LoadConfig() + dir := PickFolder("Select folder", cfg.LastPickDir) + if dir == "" { + writeJSON(w, map[string]any{"files": []any{}}) + return + } + cfg.LastPickDir = dir + _ = SaveConfig(cfg) + paths := collectHTMLFiles(dir) + files := make([]map[string]string, 0, len(paths)) + for _, p := range paths { + files = append(files, map[string]string{"path": p, "name": filepath.Base(p)}) + } + writeJSON(w, map[string]any{"files": files}) +} + func ApplovinUpload(w http.ResponseWriter, r *http.Request) { var req struct { Paths []string `json:"paths"` diff --git a/standalone/base64.go b/standalone/base64.go index 951fd97..465dee3 100644 --- a/standalone/base64.go +++ b/standalone/base64.go @@ -12,83 +12,119 @@ import ( func Base64Page(w http.ResponseWriter, r *http.Request) { body := ` -

Base64 Asset Scanner

-
- - - - -
-
-
-
+
+

Base64 Scanner

+

Scan selected HTML files for asset references that are not embedded as base64 data URIs.

+
+ +
+

Inputs

+
+
+
+ + + +
+
+
+
+
+
+
+
@@ -99,7 +135,11 @@ document.getElementById('scan').addEventListener('click', async () => { func Base64PickFolder(w http.ResponseWriter, r *http.Request) { p := PickFolder("Select folder to scan", "") - writeJSON(w, map[string]any{"path": p}) + if p == "" { + writeJSON(w, map[string]any{"paths": []string{}}) + return + } + writeJSON(w, map[string]any{"paths": collectHTMLFiles(p)}) } func Base64PickFiles(w http.ResponseWriter, r *http.Request) { diff --git a/standalone/home.go b/standalone/home.go index 26f475d..a85793d 100644 --- a/standalone/home.go +++ b/standalone/home.go @@ -12,19 +12,37 @@ func HomePage(w http.ResponseWriter, r *http.Request) { if n.Path == "/" { continue } - label := n.Label + badge := "" if n.Beta { - label += ` Beta` + badge = ` Beta` } - items.WriteString(`
  • ` + label + ` — ` + n.Description + `
  • `) + items.WriteString(`` + n.Label + badge + `` + n.Description + ``) } body := ` -

    HPL Toolbox

    -

    Standalone build. Pick a tool from the top bar.

    - +
    + ` w.Header().Set("Content-Type", "text/html; charset=utf-8") _, _ = w.Write([]byte(Page("/", "Home", body))) diff --git a/standalone/layout.go b/standalone/layout.go index 290214b..02f92d0 100644 --- a/standalone/layout.go +++ b/standalone/layout.go @@ -3,13 +3,25 @@ package main import ( "encoding/json" "net/http" - "strconv" "strings" ) const SharedCSS = ` - :root { color-scheme: dark; } + :root { + color-scheme: dark; + --tool-gap-sm: 8px; + --tool-gap-md: 12px; + --tool-gap-lg: 16px; + --tool-radius: 5px; + --tool-border: #333; + --tool-panel: #252526; + } + * { box-sizing: border-box; } + html { min-height: 100%; } body { + min-height: 100vh; + display: flex; + flex-direction: column; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #1e1e1e; color: #ddd; margin: 0; padding: 0; @@ -19,17 +31,49 @@ const SharedCSS = ` padding: 8px 16px; background: #252526; border-bottom: 1px solid #333; font-size: 13px; } - .topbar a { color: #9cdcfe; text-decoration: none; padding: 4px 10px; border-radius: 3px; } + .topbar a { color: #ddd; text-decoration: none; padding: 5px 10px; border-radius: 4px; } .topbar a:hover { background: #2a2d2e; } .topbar a.active { background: #094771; color: #fff; } .beta-pill { margin-left: 4px; padding: 1px 4px; border: 1px solid #555; border-radius: 3px; font-size: 10px; opacity: 0.7; text-transform: uppercase; } - .topbar-version { margin-left: auto; font-size: 11px; opacity: 0.45; letter-spacing: 0.4px; } - .content { padding: 16px; max-width: 980px; margin: 0 auto; } - .beta-tools-footer { max-width: 980px; margin: 24px auto 16px auto; padding: 12px 16px 0; border-top: 1px solid #333; } - .beta-tools-footer button { width: 100%; text-align: left; background: #3a3d41; color: #ddd; } - .beta-tools-footer button:hover { background: #45494e; } - .beta-note { display: block; margin-top: 3px; opacity: 0.65; font-size: 11px; } - h2 { margin-top: 0; font-weight: 500; } + .topbar-spacer { margin-left: auto; } + .content { flex: 1; width: 100%; padding: 18px; max-width: 1100px; margin: 0 auto; } + .app-footer { + width: 100%; + max-width: 1100px; + margin: auto auto 0; + padding: 8px 18px 14px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + color: #a7a7a7; + font-size: 10px; + border-top: 1px solid #333; + } + .beta-tools-toggle { + padding: 0; + background: transparent; + color: #a7a7a7; + border: 0; + cursor: pointer; + font: inherit; + opacity: 0.72; + } + .beta-tools-toggle:hover { background: transparent; opacity: 1; text-decoration: underline; } + .app-footer-version { opacity: 0.75; text-align: right; } + h2 { margin: 0; font-size: 18px; line-height: 1.25; font-weight: 600; } + .tool-header { margin-bottom: var(--tool-gap-lg); } + .tool-title { margin: 0; font-size: 18px; line-height: 1.25; font-weight: 600; } + .tool-description, .section-description, .muted { color: #a7a7a7; } + .tool-description { margin: 5px 0 0; max-width: 780px; font-size: 12px; line-height: 1.45; } + .tool-panel { margin-bottom: var(--tool-gap-lg); border: 1px solid var(--tool-border); border-radius: var(--tool-radius); background: rgba(128,128,128,0.08); overflow: hidden; } + .panel-header { padding: 10px 12px; border-bottom: 1px solid var(--tool-border); background: var(--tool-panel); } + .panel-title { margin: 0; color: #ddd; font-size: 12px; font-weight: 700; letter-spacing: 0.45px; text-transform: uppercase; } + .panel-body { padding: 12px; } + .control-group + .control-group { margin-top: var(--tool-gap-md); } + .control-label { margin: 0 0 6px; color: #a7a7a7; font-size: 11px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; } + .file-row, .field-row, .action-row { display: flex; align-items: center; gap: var(--tool-gap-sm); flex-wrap: wrap; } + .action-row { margin-top: var(--tool-gap-md); } input[type=text], input[type=date], select, textarea { box-sizing: border-box; padding: 6px 8px; background: #3c3c3c; color: #ddd; @@ -46,7 +90,30 @@ const SharedCSS = ` button:hover { background: #1177bb; } button.secondary { background: #3a3d41; color: #ddd; } button.secondary:hover { background: #45494e; } + button.danger { background: transparent; color: #f48771; border: 1px solid #444; } + button.danger:hover { background: rgba(244,135,113,0.14); } button:disabled { opacity: 0.5; cursor: not-allowed; } + .status-panel, .results-panel, .result-card { border: 1px solid var(--tool-border); border-radius: var(--tool-radius); background: rgba(128,128,128,0.08); } + .status-panel { min-height: 30px; margin-top: var(--tool-gap-md); padding: 8px 10px; white-space: pre-wrap; } + .status-panel:empty { display: none; } + .results-panel { margin-top: var(--tool-gap-md); overflow: auto; } + .results-panel:empty { display: none; } + .result-card { padding: 10px; word-break: break-word; } + .data-table { width: 100%; border-collapse: collapse; table-layout: fixed; } + .data-table th, .data-table td { padding: 8px 10px; text-align: left; vertical-align: top; border-bottom: 1px solid var(--tool-border); } + .data-table th { color: #a7a7a7; font-size: 11px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase; background: var(--tool-panel); } + .data-table tr:last-child td { border-bottom: none; } + .mono { font-family: Consolas, "Courier New", monospace; font-size: 12px; } + .wrap { overflow-wrap: anywhere; word-break: break-word; } + .file-name { color: #a7a7a7; font-size: 12px; overflow-wrap: anywhere; } + .selected-list, .selected-files { margin-top: 8px; } + .remove-selected, .remove-btn { min-width: 28px; width: 28px; padding: 3px 0; color: #f48771; font-size: 16px; line-height: 1; } + .pager { margin-top: 8px; display: flex; align-items: center; gap: 8px; justify-content: flex-end; } + .badge { display: inline-flex; align-items: center; min-height: 18px; padding: 1px 6px; border-radius: 999px; border: 1px solid #444; font-size: 11px; line-height: 1.2; white-space: nowrap; } + .badge.ok { color: #89d185; background: rgba(137,209,133,0.12); } + .badge.err { color: #f48771; background: rgba(244,135,113,0.14); } + .badge.warn { color: #ffd580; background: rgba(210,153,34,0.16); } + .is-hidden { display: none !important; } .err { color: #f48771; white-space: pre-wrap; } .ok { color: #89d185; } .hint { font-size: 12px; opacity: 0.7; } @@ -62,7 +129,7 @@ type navItem struct { var navItems = []navItem{ {Path: "/", Label: "Home"}, {Path: "/plec", Label: "PLEC Upload", Description: "Upload HTML to the internal PLEC server"}, - {Path: "/applovin", Label: "AppLovin Upload", Description: "Upload to p.applov.in (QR preview)"}, + {Path: "/applovin", Label: "AppLovin Playable Preview", Description: "Upload to p.applov.in (QR preview)"}, {Path: "/base64", Label: "Base64 Scanner", Description: "Find non-base64 assets in HTML"}, {Path: "/mraid", Label: "MRAID Checker", Description: "Check MRAID requirements and best practices", Beta: true}, {Path: "/mobile", Label: "Send To Mobile", Description: "Share HTML to a phone via LAN + QR"}, @@ -118,11 +185,9 @@ func Page(activePath, title, body string) string { tabs.WriteString(`` + label + ``) } - betaButtonLabel := "Enable Beta Tools" - betaButtonNote := "Hidden beta tools: " + strconv.Itoa(betaToolCount()) + betaButtonLabel := "Show beta" if betaToolsEnabled { - betaButtonLabel = "Disable Beta Tools" - betaButtonNote = "Beta tools are visible in this standalone launcher." + betaButtonLabel = "Hide beta" } return ` @@ -131,10 +196,11 @@ func Page(activePath, title, body string) string { ` + title + ` — HPL Toolbox -
    ` + tabs.String() + `v` + AppVersion + `
    +
    ` + tabs.String() + `
    ` + body + `
    -