diff --git a/.eslintignore b/.eslintignore
index 1e9949e11e..2019b0d18c 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1613,4 +1613,7 @@ packages/tools/release-server.js.map
packages/tools/tool-utils.d.ts
packages/tools/tool-utils.js
packages/tools/tool-utils.js.map
+packages/tools/update-readme-sponsors.d.ts
+packages/tools/update-readme-sponsors.js
+packages/tools/update-readme-sponsors.js.map
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
diff --git a/.gitignore b/.gitignore
index d070efdeee..c80170011f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1599,4 +1599,7 @@ packages/tools/release-server.js.map
packages/tools/tool-utils.d.ts
packages/tools/tool-utils.js
packages/tools/tool-utils.js.map
+packages/tools/update-readme-sponsors.d.ts
+packages/tools/update-readme-sponsors.js
+packages/tools/update-readme-sponsors.js.map
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
diff --git a/README.md b/README.md
index a3e7bb2067..eb93ca942c 100644
--- a/README.md
+++ b/README.md
@@ -68,13 +68,15 @@ The Web Clipper is a browser extension that allows you to save web pages and scr
* * *
-| | | |
-| :---: | :---: | :---: |
-| [Devon Zuegel](https://github.com/devonzuegel) | [小西 孝宗](https://github.com/konishi-t) | [Alexander van der Berg](https://github.com/avanderberg)
-| [Nicholas Head](https://github.com/nicholashead) | [Frank Bloise](https://github.com/fbloise) | [Thomas Broussard](https://github.com/thomasbroussard)
-| [Brandon Johnson](https://github.com/dbrandonjohnson) | [@cnagy](https://github.com/c-nagy) | [clmntsl](https://github.com/clmntsl)
-| [mcejp](https://github.com/mcejp) | [joesfer](https://github.com/joesfer) | [chr15m](https://github.com/chr15m)
-| [piccobit](https://github.com/piccobit) | [Jess Sullivan](https://github.com/jesssullivan)
+
+| | | | |
+| :---: | :---: | :---: | :---: |
+| [avanderberg](https://github.com/avanderberg) | [c-nagy](https://github.com/c-nagy) | [cabottech](https://github.com/cabottech) | [chr15m](https://github.com/chr15m) |
+| [chrootlogin](https://github.com/chrootlogin) | [dbrandonjohnson](https://github.com/dbrandonjohnson) | [fbloise](https://github.com/fbloise) | [h4sh5](https://github.com/h4sh5) |
+| [Jesssullivan](https://github.com/Jesssullivan) | [joesfer](https://github.com/joesfer) | [konishi-t](https://github.com/konishi-t) | [maxtruxa](https://github.com/maxtruxa) |
+| [mcejp](https://github.com/mcejp) | [nicholashead](https://github.com/nicholashead) | [piccobit](https://github.com/piccobit) | [ravenscroftj](https://github.com/ravenscroftj) |
+| [thismarty](https://github.com/thismarty) | [thomasbroussard](https://github.com/thomasbroussard) | [wasteisobscene](https://github.com/wasteisobscene) | |
+
# Table of contents
diff --git a/packages/lib/markdownUtils.ts b/packages/lib/markdownUtils.ts
index a7df5b5389..17ad71f9ca 100644
--- a/packages/lib/markdownUtils.ts
+++ b/packages/lib/markdownUtils.ts
@@ -7,10 +7,18 @@ const MarkdownIt = require('markdown-it');
const listRegex = /^(\s*)([*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]\s))(\s*)/;
const emptyListRegex = /^(\s*)([*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s+)$/;
+export enum MarkdownTableJustify {
+ Left = 'left',
+ Center = 'center',
+ Right = 'right,',
+}
+
export interface MarkdownTableHeader {
name: string;
label: string;
filter?: Function;
+ disableEscape?: boolean;
+ justify?: MarkdownTableJustify;
}
export interface MarkdownTableRow {
@@ -120,26 +128,38 @@ const markdownUtils = {
createMarkdownTable(headers: MarkdownTableHeader[], rows: MarkdownTableRow[]): string {
const output = [];
+ const minCellWidth = 5;
+
const headersMd = [];
const lineMd = [];
for (let i = 0; i < headers.length; i++) {
const h = headers[i];
- headersMd.push(stringPadding(h.label, 3, ' ', stringPadding.RIGHT));
- lineMd.push('---');
+ headersMd.push(stringPadding(h.label, minCellWidth, ' ', stringPadding.RIGHT));
+
+ const justify = h.justify ? h.justify : MarkdownTableJustify.Left;
+
+ if (justify === MarkdownTableJustify.Left) {
+ lineMd.push('-----');
+ } else if (justify === MarkdownTableJustify.Center) {
+ lineMd.push(':---:');
+ } else {
+ lineMd.push('----:');
+ }
}
- output.push(headersMd.join(' | '));
- output.push(lineMd.join(' | '));
+ output.push(`| ${headersMd.join(' | ')} |`);
+ output.push(`| ${lineMd.join(' | ')} |`);
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
const rowMd = [];
for (let j = 0; j < headers.length; j++) {
const h = headers[j];
- const valueMd = markdownUtils.escapeTableCell(h.filter ? h.filter(row[h.name]) : row[h.name]);
- rowMd.push(stringPadding(valueMd, 3, ' ', stringPadding.RIGHT));
+ const value = (h.filter ? h.filter(row[h.name]) : row[h.name]) || '';
+ const valueMd = h.disableEscape ? value : markdownUtils.escapeTableCell(value);
+ rowMd.push(stringPadding(valueMd, minCellWidth, ' ', stringPadding.RIGHT));
}
- output.push(rowMd.join(' | '));
+ output.push(`| ${rowMd.join(' | ')} |`);
}
return output.join('\n');
diff --git a/packages/tools/build-all.sh b/packages/tools/build-all.sh
index 94aa536e91..fb8edac45a 100755
--- a/packages/tools/build-all.sh
+++ b/packages/tools/build-all.sh
@@ -20,6 +20,11 @@ echo "$ROOT_DIR/build-welcome.js..."
echo "---------------------------------------------------"
node "$ROOT_DIR/build-welcome.js"
+echo "---------------------------------------------------"
+echo "$ROOT_DIR/update-readme-sponsors.js..."
+echo "---------------------------------------------------"
+node "$ROOT_DIR/update-readme-sponsors.js"
+
cd "$ROOT_DIR/.."
echo "---------------------------------------------------"
echo "npm run buildWebsite..."
diff --git a/packages/tools/sponsors.json b/packages/tools/sponsors.json
new file mode 100644
index 0000000000..e504d9263b
--- /dev/null
+++ b/packages/tools/sponsors.json
@@ -0,0 +1,80 @@
+{
+ "github": [
+ {
+ "name": "nicholashead",
+ "id": "1168659"
+ },
+ {
+ "name": "avanderberg",
+ "id": "215668"
+ },
+ {
+ "name": "fbloise",
+ "id": "1439535"
+ },
+ {
+ "name": "thomasbroussard",
+ "id": "15859362"
+ },
+ {
+ "name": "dbrandonjohnson",
+ "id": "1307332"
+ },
+ {
+ "name": "c-nagy",
+ "id": "3061769"
+ },
+ {
+ "name": "wasteisobscene",
+ "id": "53228972"
+ },
+ {
+ "name": "mcejp",
+ "id": "29300939"
+ },
+ {
+ "name": "joesfer",
+ "id": "1248504"
+ },
+ {
+ "name": "chr15m",
+ "id": "67130"
+ },
+ {
+ "name": "piccobit",
+ "id": "5782817"
+ },
+ {
+ "name": "chrootlogin",
+ "id": "4862947"
+ },
+ {
+ "name": "maxtruxa",
+ "id": "1788010"
+ },
+ {
+ "name": "Jesssullivan",
+ "id": "37297218"
+ },
+ {
+ "name": "cabottech",
+ "id": "70780798"
+ },
+ {
+ "name": "h4sh5",
+ "id": "38898566"
+ },
+ {
+ "name": "ravenscroftj",
+ "id": "47742"
+ },
+ {
+ "name": "thismarty",
+ "id": "73081837"
+ },
+ {
+ "name": "konishi-t",
+ "id": "24908652"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/tools/update-readme-sponsors.ts b/packages/tools/update-readme-sponsors.ts
new file mode 100644
index 0000000000..10b89c9ec7
--- /dev/null
+++ b/packages/tools/update-readme-sponsors.ts
@@ -0,0 +1,65 @@
+import { readFile } from 'fs-extra';
+import { insertContentIntoFile, rootDir } from './tool-utils';
+import markdownUtils, { MarkdownTableHeader, MarkdownTableJustify, MarkdownTableRow } from '@joplin/lib/markdownUtils';
+
+const readmePath = `${rootDir}/README.md`;
+const sponsorsPath = `${rootDir}/packages/tools/sponsors.json`;
+
+interface Sponsor {
+ name: string;
+ id: string;
+}
+
+async function main() {
+ const sponsors: Sponsor[] = (JSON.parse(await readFile(sponsorsPath, 'utf8'))).github;
+
+ sponsors.sort((a, b) => {
+ return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : +1;
+ });
+
+ const sponsorsPerRow = 4;
+
+ const headers: MarkdownTableHeader[] = [];
+
+ for (let colIndex = 0; colIndex < sponsorsPerRow; colIndex++) {
+ headers.push({
+ label: '',
+ name: `col${colIndex}`,
+ disableEscape: true,
+ justify: MarkdownTableJustify.Center,
+ });
+ }
+
+ const rows: MarkdownTableRow[] = [];
+
+ let sponsorIndex = 0;
+ for (let rowIndex = 0; rowIndex < 9999; rowIndex++) {
+ let sponsor = null;
+ const row: MarkdownTableRow = {};
+ for (let colIndex = 0; colIndex < sponsorsPerRow; colIndex++) {
+ sponsor = sponsors[sponsorIndex];
+ sponsorIndex++;
+ if (!sponsor) break;
+
+ row[`col${colIndex}`] = `[${sponsor.name}](https://github.com/${sponsor.name})`;
+ }
+
+ if (Object.keys(row)) rows.push(row);
+
+ if (!sponsor) break;
+ }
+
+ const mdTable = markdownUtils.createMarkdownTable(headers, rows);
+
+ await insertContentIntoFile(
+ readmePath,
+ '\n',
+ '\n',
+ mdTable
+ );
+}
+
+main().catch((error) => {
+ console.error('Fatal error', error);
+ process.exit(1);
+});