From 2babb71c7abb6a744857b4d5e62448c7c66a9ee0 Mon Sep 17 00:00:00 2001 From: Marco Russo Date: Fri, 21 Aug 2026 12:02:42 +0200 Subject: [PATCH 1/3] Restore the dry privacy copy, and keep the FAQ in step The privacy lede had become a summary of the whole page. Put the two-sentence lede back, keep the version-check facts, and stop the FAQ and changelog from naming GitHub as the check host or claiming no stable release exists. --- site/changelog.html | 2 +- site/faq.html | 4 ++-- site/privacy.html | 9 ++++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/site/changelog.html b/site/changelog.html index d1ed243..38951e2 100644 --- a/site/changelog.html +++ b/site/changelog.html @@ -48,7 +48,7 @@

Two channels

The released installer is SQLBI Whiteboard. The pre-release installer is SQLBI Whiteboard (Dev). They are separate products: different folders, different settings, different upgrade codes. Only the released channel registers .wboard and .wimport, so uninstalling Dev cannot break those associations.

Published builds

-

Until a stable release exists, the list below is pre-release builds. Without scripting, use All releases.

+

Without scripting, use All releases.

diff --git a/site/faq.html b/site/faq.html index 1d8da81..2dd56dd 100644 --- a/site/faq.html +++ b/site/faq.html @@ -63,13 +63,13 @@

Mac, iPad, or a browser?

No. It is a Windows application. Boards are files you can keep next to the material they document; they do not open in a browser.

Does it need an account, a tenant, or the internet?

-

No account, no tenant. Boards and preferences stay on this machine. A copy that did not come from the Microsoft Store may ask GitHub once a day whether a newer released build exists; a bar under the tabs offers the download site if one does. Turn that off in Help → Preferences → Updates. A Microsoft Store install never makes that request. Details are on Privacy.

+

No account, no tenant. Boards and preferences stay on this machine. A copy that did not come from the Microsoft Store may check this site once a day for a newer released build; a bar under the tabs offers the download site if one does. Turn that off in Help → Preferences → Updates. A Microsoft Store install never makes that request. Details are on Privacy.

Where do boards live? What is a .wboard?

A board is a file on disk. Save writes a versioned ZIP with an embedded preview.png. Explorer shows that picture as the thumbnail in the released install. The VS Code extension shows the same picture.

Can Released and Dev both be installed?

-

Yes. The pre-release installs as SQLBI Whiteboard (Dev), keeps its own settings, and does not register .wboard or .wimport, so it can sit beside a released copy without stealing the file association. Until a stable release exists, the download on the home page is the latest pre-release and says so.

+

Yes. The pre-release installs as SQLBI Whiteboard (Dev), keeps its own settings, and does not register .wboard or .wimport, so it can sit beside a released copy without stealing the file association.

What is LiveView, and why Reconnect after open?

LiveView captures a window or a display onto the board so you can draw over it. Windows cannot save the capture permission. After you reload a board the last frame appears immediately; Reconnect restores the live feed. The guide has the session story.

diff --git a/site/privacy.html b/site/privacy.html index 21669b5..a6c8b96 100644 --- a/site/privacy.html +++ b/site/privacy.html @@ -37,7 +37,7 @@
Project

Privacy

-

The application does not create an account or send telemetry. A Microsoft Store install never phones home. Any other copy may ask GitHub once a day whether a newer released build exists; that check can be turned off.

+

The application does not send telemetry. This page is what the website and the installer actually do.

@@ -46,16 +46,15 @@

Privacy

The application

SQLBI Whiteboard does not create an account, does not join a tenant, and does not send telemetry. There is no Application Insights, no crash reporter, and no outbound product analytics in the source.

-

A copy that did not come from the Microsoft Store, with Check for new versions on (the default), makes at most one GET a day to whiteboard.sqlbi.com for stable.json, the same short file this site publishes for its own download links. A pre-release copy reads dev.json instead. If that request fails, it makes one to github.com to read the tag of the newest release. Either way it reads a version number and nothing else.

-

The request identifies the product version in the User-Agent; it does not send a machine identifier, a board, or preferences. A Microsoft Store install never makes that request; the Store updates it. Turn the check off under Help → Preferences → Updates.

+

A copy that did not come from the Microsoft Store, with Check for new versions on (the default), makes at most one GET a day to this site for stable.json, or dev.json for a pre-release copy. That is the same file the download page uses. If the request fails, it asks github.com for the newest release tag. Either way it reads a version number. The User-Agent carries the product version. Nothing else is sent. A Microsoft Store install never makes that request. Turn the check off under Help → Preferences → Updates.

Boards are local .wboard files. Preferences live under %APPDATA%\SQLBI\Whiteboard (or Whiteboard Dev for the pre-release channel).

LiveView uses Windows Graphics Capture on this machine. The capture permission cannot be saved with the file. After you reload a board, the last frame is shown from the file; Reconnect asks Windows again.

This website

The site is static HTML on GitHub Pages. It does not set a first-party cookie and it has no consent banner.

From be3761bc0c5f1c194fd224ddda59938c84f91903 Mon Sep 17 00:00:00 2001 From: Marco Russo Date: Fri, 21 Aug 2026 14:44:25 +0200 Subject: [PATCH 2/3] Render changelog notes as markdown, and split the version-check copy Release notes are PR markdown dumped into a pre block. Render headings, lists, code, and links, and join the 72-column wraps. Split the privacy version-check wall into what the user can do and what the request sends. --- site/changelog.html | 144 ++++++++++++++++++++++++++++++++++++++++---- site/privacy.html | 3 +- site/styles.css | 30 ++++++++- 3 files changed, 161 insertions(+), 16 deletions(-) diff --git a/site/changelog.html b/site/changelog.html index 38951e2..a8a56d6 100644 --- a/site/changelog.html +++ b/site/changelog.html @@ -95,6 +95,7 @@

Published builds

(function () { var list = document.getElementById('releases'); var note = document.getElementById('release-note'); + var ISSUES = 'https://github.com/sql-bi/SQLBI-Whiteboard/issues/'; fetch('https://api.github.com/repos/sql-bi/SQLBI-Whiteboard/releases?per_page=20') .then(function (response) { @@ -120,13 +121,133 @@

Published builds

}); } - function firstLine(text) { + function stripTrailers(text) { var lines = String(text).replace(/\r\n/g, '\n').split('\n'); - for (var i = 0; i < lines.length; i++) { - var line = lines[i].replace(/^#+\s*/, '').trim(); - if (line) return line; + while (lines.length) { + var t = lines[lines.length - 1].trim(); + if (!t || /^Co-authored-by:/i.test(t) || /^Signed-off-by:/i.test(t) || /^-{3,}$/.test(t)) { + lines.pop(); + continue; + } + break; + } + return lines.join('\n').trim(); + } + + function splitNotes(text) { + var lines = String(text).replace(/\r\n/g, '\n').split('\n'); + var i = 0; + while (i < lines.length && !lines[i].trim()) i++; + var sum = (lines[i] || '').replace(/^#+\s*/, '').trim(); + i++; + while (i < lines.length && !lines[i].trim()) i++; + return { sum: sum, rest: stripTrailers(lines.slice(i).join('\n')) }; + } + + function inline(s) { + var slots = []; + function keep(html) { + slots.push(html); + return '\0' + (slots.length - 1) + '\0'; + } + s = s.replace(/`([^`]+)`/g, function (_, c) { + return keep('' + c + ''); + }); + s = s.replace(/\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)/g, function (_, t, u) { + return keep('' + t + ''); + }); + s = s.replace(/(^|[\s(])(https?:\/\/[^\s<]+[^.\s<),])/g, function (_, p, u) { + return p + keep('' + u + ''); + }); + s = s.replace(/\*\*([^*]+)\*\*/g, '$1'); + s = s.replace(/(^|[\s(])\*([^*\s][^*]*)\*/g, '$1$2'); + s = s.replace(/(^|[\s(])#(\d+)\b/g, function (_, p, n) { + return p + '#' + n + ''; + }); + return s.replace(/\0(\d+)\0/g, function (_, i) { return slots[+i]; }); + } + + function md(src) { + var lines = esc(src).split('\n'); + var out = []; + var i = 0; + + function peek() { return i < lines.length ? lines[i] : null; } + function blank(line) { return !line || !String(line).trim(); } + function isHeading(line) { return /^(#{1,6})\s+\S/.test(line); } + function isHr(line) { return /^(-{3,}|_{3,}|\*{3,})\s*$/.test(String(line || '').trim()); } + function isUl(line) { return /^[-*+]\s+\S/.test(line); } + function isOl(line) { return /^\d+[.)]\s+\S/.test(line); } + function isFence(line) { return /^```/.test(line); } + + function takeFence() { + i++; + var body = []; + while (i < lines.length && !/^```/.test(lines[i])) { + body.push(lines[i]); + i++; + } + if (i < lines.length) i++; + return '
' + body.join('\n') + '
'; + } + + function takeList(ordered) { + var tag = ordered ? 'ol' : 'ul'; + var re = ordered ? /^\d+[.)]\s+/ : /^[-*+]\s+/; + var items = []; + while (i < lines.length) { + if (blank(peek())) { + var j = i + 1; + while (j < lines.length && blank(lines[j])) j++; + if (j < lines.length && re.test(lines[j])) { i = j; continue; } + break; + } + if (isFence(peek()) || isHeading(peek()) || isHr(peek())) break; + if (re.test(peek())) { + items.push(peek().replace(re, '')); + i++; + continue; + } + if (items.length) { + items[items.length - 1] += ' ' + peek().trim(); + i++; + continue; + } + break; + } + return '<' + tag + '>' + items.map(function (it) { + return '
  • ' + inline(it.trim()) + '
  • '; + }).join('') + ''; + } + + function takeParagraph() { + var buf = []; + while (i < lines.length && !blank(peek())) { + if (isFence(peek()) || isHeading(peek()) || isHr(peek()) || + isUl(peek()) || isOl(peek())) break; + buf.push(peek().trim()); + i++; + } + return '

    ' + inline(buf.join(' ')) + '

    '; + } + + while (i < lines.length) { + var line = peek(); + if (blank(line)) { i++; continue; } + if (isFence(line)) { out.push(takeFence()); continue; } + if (isHeading(line)) { + var m = line.match(/^(#{1,6})\s+(.*)$/); + var lvl = Math.min(m[1].length, 3); + out.push('' + inline(m[2].trim()) + ''); + i++; + continue; + } + if (isHr(line)) { out.push('
    '); i++; continue; } + if (isUl(line)) { out.push(takeList(false)); continue; } + if (isOl(line)) { out.push(takeList(true)); continue; } + out.push(takeParagraph()); } - return ''; + return out.join(''); } function notesFor(release) { @@ -151,17 +272,16 @@

    Published builds

    var when = new Date(r.published_at).toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' }); - var full = notes[i] || ''; - var sum = firstLine(full); + var parts = splitNotes(notes[i] || ''); html += '
  • '; - if (sum) { - html += '

    ' + esc(sum) + '

    '; + if (parts.sum) { + html += '

    ' + esc(parts.sum) + '

    '; } - if (full && full.replace(/\r\n/g, '\n').trim() !== sum) { - html += '
    Notes
    ' +
    -                esc(full.trim()) + '
    '; + if (parts.rest) { + html += '
    Notes
    ' + + md(parts.rest) + '
    '; } html += '
  • '; } diff --git a/site/privacy.html b/site/privacy.html index a6c8b96..12cea80 100644 --- a/site/privacy.html +++ b/site/privacy.html @@ -46,7 +46,8 @@

    Privacy

    The application

    SQLBI Whiteboard does not create an account, does not join a tenant, and does not send telemetry. There is no Application Insights, no crash reporter, and no outbound product analytics in the source.

    -

    A copy that did not come from the Microsoft Store, with Check for new versions on (the default), makes at most one GET a day to this site for stable.json, or dev.json for a pre-release copy. That is the same file the download page uses. If the request fails, it asks github.com for the newest release tag. Either way it reads a version number. The User-Agent carries the product version. Nothing else is sent. A Microsoft Store install never makes that request. Turn the check off under Help → Preferences → Updates.

    +

    A Microsoft Store install never phones home. The Store updates it. Any other copy may ask this site once a day whether a newer build exists. That check is on by default; turn it off under Help → Preferences → Updates.

    +

    The request is a GET of stable.json, or dev.json for a pre-release copy, the same file the download page uses. If it fails, a request to github.com for the newest release tag. The User-Agent carries the product version. Nothing else is sent.

    Boards are local .wboard files. Preferences live under %APPDATA%\SQLBI\Whiteboard (or Whiteboard Dev for the pre-release channel).

    LiveView uses Windows Graphics Capture on this machine. The capture permission cannot be saved with the file. After you reload a board, the last frame is shown from the file; Reconnect asks Windows again.

    diff --git a/site/styles.css b/site/styles.css index 8da2ed3..f14c314 100644 --- a/site/styles.css +++ b/site/styles.css @@ -805,12 +805,36 @@ footer a:hover { color: var(--ink); text-decoration: underline; } .releases details[open] summary::after { content: " \2212"; } .relbody { margin: 10px 0 0; - font: inherit; - font-size: 14px; + font-size: 14.5px; line-height: 1.55; - white-space: pre-wrap; color: var(--ink); } +.relbody > *:first-child { margin-top: 0; } +.relbody > *:last-child { margin-bottom: 0; } +.relbody h1, .relbody h2, .relbody h3 { + font-size: 14.5px; + font-weight: 650; + margin: 1.05em 0 .35em; +} +.relbody p { margin: 0 0 .7em; } +.relbody ul, .relbody ol { margin: 0 0 .7em; padding-left: 1.25em; } +.relbody li { margin: .2em 0; } +.relbody a { color: var(--brand-link); text-underline-offset: 2px; } +.relbody hr { + border: 0; + border-top: 1px solid var(--line); + margin: .9em 0; +} +.relbody pre { + margin: 0 0 .7em; + padding: 10px 12px; + font-size: 13px; + line-height: 1.45; + white-space: pre-wrap; + background: var(--surface-2); + border: 1px solid var(--line); + border-radius: 10px; +} .compare { font-size: 14.5px; } .compare th:nth-child(2), From 9c7bb667db58923e8faa3b1eef3d8241346231f0 Mon Sep 17 00:00:00 2001 From: Marco Russo Date: Fri, 21 Aug 2026 14:53:52 +0200 Subject: [PATCH 3/3] Inset changelog notes, and list the version-check steps Expanded release notes ran into the next version. They now sit in an indented, quieter panel so the version row stays the landmark. The privacy version-check is a short lead-in plus the four steps as bullets. --- site/privacy.html | 9 +++++++-- site/styles.css | 15 ++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/site/privacy.html b/site/privacy.html index 12cea80..362cfcb 100644 --- a/site/privacy.html +++ b/site/privacy.html @@ -46,8 +46,13 @@

    Privacy

    The application

    SQLBI Whiteboard does not create an account, does not join a tenant, and does not send telemetry. There is no Application Insights, no crash reporter, and no outbound product analytics in the source.

    -

    A Microsoft Store install never phones home. The Store updates it. Any other copy may ask this site once a day whether a newer build exists. That check is on by default; turn it off under Help → Preferences → Updates.

    -

    The request is a GET of stable.json, or dev.json for a pre-release copy, the same file the download page uses. If it fails, a request to github.com for the newest release tag. The User-Agent carries the product version. Nothing else is sent.

    +

    A Microsoft Store install never phones home. The Store updates it. Any other copy may ask this site once a day whether a newer build exists.

    +
      +
    • Check for new versions is on by default; turn it off under Help → Preferences → Updates.
    • +
    • A GET of stable.json, or dev.json for a pre-release copy, the same file the download page uses.
    • +
    • If that fails, a request to github.com for the newest release tag.
    • +
    • The User-Agent carries the product version. Nothing else is sent.
    • +

    Boards are local .wboard files. Preferences live under %APPDATA%\SQLBI\Whiteboard (or Whiteboard Dev for the pre-release channel).

    LiveView uses Windows Graphics Capture on this machine. The capture permission cannot be saved with the file. After you reload a board, the last frame is shown from the file; Reconnect asks Windows again.

    diff --git a/site/styles.css b/site/styles.css index f14c314..f61ad3c 100644 --- a/site/styles.css +++ b/site/styles.css @@ -772,7 +772,7 @@ footer a:hover { color: var(--ink); text-decoration: underline; } background: var(--surface); box-shadow: var(--shadow-sm); } -.releases li { border-bottom: 1px solid var(--line); padding: 14px 18px; } +.releases li { border-bottom: 1px solid var(--line); padding: 16px 18px 18px; } .releases li:last-child { border-bottom: 0; } .reltop { display: flex; @@ -792,7 +792,7 @@ footer a:hover { color: var(--ink); text-decoration: underline; } overflow: hidden; text-overflow: ellipsis; } -.releases details { margin-top: 8px; } +.releases details { margin: 10px 0 0 12px; } .releases summary { cursor: pointer; color: var(--brand-link); @@ -804,16 +804,20 @@ footer a:hover { color: var(--ink); text-decoration: underline; } .releases summary::after { content: " +"; font-weight: 500; } .releases details[open] summary::after { content: " \2212"; } .relbody { - margin: 10px 0 0; + margin: 8px 0 0; + padding: 12px 16px; + background: var(--surface-2); + border-radius: 10px; font-size: 14.5px; line-height: 1.55; - color: var(--ink); + color: var(--muted); } .relbody > *:first-child { margin-top: 0; } .relbody > *:last-child { margin-bottom: 0; } .relbody h1, .relbody h2, .relbody h3 { font-size: 14.5px; font-weight: 650; + color: var(--ink); margin: 1.05em 0 .35em; } .relbody p { margin: 0 0 .7em; } @@ -831,9 +835,10 @@ footer a:hover { color: var(--ink); text-decoration: underline; } font-size: 13px; line-height: 1.45; white-space: pre-wrap; - background: var(--surface-2); + background: var(--surface); border: 1px solid var(--line); border-radius: 10px; + color: var(--ink); } .compare { font-size: 14.5px; }