A color scheme for you to love. ♡ https://love.holllo.cc
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

189 lines
5.7 KiB

  1. import fs, {promises as fsp} from 'fs';
  2. import {join} from 'path';
  3. import cpy from 'cpy';
  4. // @ts-expect-error
  5. import htmlclean from 'htmlclean';
  6. import marked from 'marked';
  7. import nunjucks from 'nunjucks';
  8. import refractor from 'refractor';
  9. import rehype from 'rehype';
  10. import sass from 'sass';
  11. import {generateLove, LoveVariant} from './love';
  12. import {getVersions, Versions} from './version';
  13. export async function main(): Promise<void> {
  14. // Create all required directories for the website.
  15. await fsp.mkdir(join(__dirname, '../../public/css/'), {recursive: true});
  16. await fsp.copyFile(
  17. join(__dirname, '../../node_modules/modern-normalize/modern-normalize.css'),
  18. join(__dirname, '../../public/css/modern-normalize.css')
  19. );
  20. await fsp.mkdir(join(__dirname, '../../public/images/'), {recursive: true});
  21. // Configure Nunjucks to use the templates for `source/pages/`.
  22. nunjucks.configure(join(__dirname, '../pages/'), {
  23. lstripBlocks: true,
  24. trimBlocks: true,
  25. throwOnUndefined: true
  26. });
  27. const love: LoveVariant[] = generateLove();
  28. const versions: Versions = await getVersions();
  29. // Write the colors to file.
  30. await writeJSON(join(__dirname, '../../public/love.json'), love);
  31. // Render the Sass to CSS.
  32. let css: string = sass
  33. .renderSync({
  34. file: join(__dirname, '../pages/scss/style.scss'),
  35. sourceMap: false
  36. })
  37. .css.toString();
  38. // Generate the CSS custom properties.
  39. const cssProperties = `:root {
  40. --foreground-1: ${love[0].colors.foreground1};
  41. --foreground-2: ${love[0].colors.foreground2};
  42. --background-1: ${love[0].colors.background1};
  43. --background-2: ${love[0].colors.background2};
  44. ${love[0].colors.accents
  45. .map((value, index) => ` --dark-accent-${index + 1}: ${value};`)
  46. .join('\n')}
  47. ${love[0].colors.grays
  48. .map((value, index) => ` --dark-gray-${index + 1}: ${value};`)
  49. .join('\n')}
  50. ${love[1].colors.accents
  51. .map((value, index) => ` --light-accent-${index + 1}: ${value};`)
  52. .join('\n')}
  53. ${love[1].colors.grays
  54. .map((value, index) => ` --light-gray-${index + 1}: ${value};`)
  55. .join('\n')}
  56. }\n`;
  57. // Replace the predefined `:root` location with our properties.
  58. css = css.replace(/\/\* :root-insert \*\//, cssProperties);
  59. // Write the CSS to file.
  60. await fsp.writeFile(join(__dirname, '../../public/css/style.css'), css);
  61. // Render and write the `index.html` file.
  62. await fsp.writeFile(
  63. join(__dirname, '../../public/index.html'),
  64. htmlclean(nunjucks.render('index.html', {love}))
  65. );
  66. const renderer: marked.Renderer = new marked.Renderer();
  67. renderer.code = (code: string, language: string | undefined): string => {
  68. if (language === undefined) {
  69. throw new Error('Markdown code block with no language detected');
  70. }
  71. const codeHTML: string = rehype()
  72. .stringify({type: 'root', children: refractor.highlight(code, language)})
  73. .toString();
  74. return `<pre><code class="language-${language}">${codeHTML}</code></pre>`;
  75. };
  76. await fsp.mkdir(join(__dirname, '../../public/get/'), {recursive: true});
  77. const pagesToCreate: string[] = (
  78. await fsp.readdir(join(__dirname, '../'))
  79. ).filter((value) => !['pages', 'scripts'].includes(value));
  80. for (const page of pagesToCreate) {
  81. const markdown: string = marked(
  82. nunjucks.renderString(
  83. await fsp.readFile(
  84. join(__dirname, `../${page}/SITE README.md`),
  85. 'utf8'
  86. ),
  87. {versions}
  88. ),
  89. {renderer}
  90. );
  91. await fsp.mkdir(join(__dirname, `../../public/images/${page}/`), {
  92. recursive: true
  93. });
  94. if (fs.existsSync(join(__dirname, `../${page}/images/`))) {
  95. await cpy(
  96. join(__dirname, `../${page}/images/*`),
  97. join(__dirname, `../../public/images/${page}/`)
  98. );
  99. }
  100. let title = `Love for ${page
  101. .replace(/-/g, ' ')
  102. .split(' ')
  103. .map((value) => capitalize(value))
  104. .join(' ')}`;
  105. switch (page) {
  106. case 'vscode':
  107. title = 'Love for VS Code';
  108. break;
  109. default:
  110. break;
  111. }
  112. const directory = join(__dirname, `../../public/get/${page}/`);
  113. await fsp.mkdir(directory, {recursive: true});
  114. await fsp.writeFile(
  115. join(directory, 'index.html'),
  116. htmlclean(nunjucks.render('get.html', {love, markdown, title}))
  117. );
  118. }
  119. await writeCustomProperties(love, versions['css-custom-properties']);
  120. }
  121. export function capitalize(word: string): string {
  122. return `${word.slice(0, 1).toUpperCase()}${word.slice(1)}`;
  123. }
  124. // Utility helper function to write some data to file as JSON.
  125. export async function writeJSON(path: string, data: unknown): Promise<void> {
  126. await fsp.writeFile(path, JSON.stringify(data, null, 2));
  127. }
  128. export async function writeCustomProperties(
  129. love: LoveVariant[],
  130. version: string
  131. ): Promise<void> {
  132. let css = `/*
  133. The Love Theme CSS Custom Properties
  134. https://love.holllo.cc - version ${version}
  135. MIT license
  136. */
  137. .love {\n`;
  138. for (const variant of love) {
  139. const prefix = variant.name === 'dark' ? 'd' : 'l';
  140. css += ` /* Love ${capitalize(variant.name)} */\n`;
  141. css += ` --${prefix}f-1: ${variant.colors.foreground1};\n`;
  142. css += ` --${prefix}f-2: ${variant.colors.foreground2};\n`;
  143. css += ` --${prefix}b-1: ${variant.colors.background1};\n`;
  144. css += ` --${prefix}b-2: ${variant.colors.background2};\n`;
  145. for (const [index, color] of variant.colors.accents.entries()) {
  146. css += ` --${prefix}a-${index + 1}: ${color};\n`;
  147. }
  148. for (const [index, color] of variant.colors.grays.entries()) {
  149. css += ` --${prefix}g-${index + 1}: ${color};\n`;
  150. }
  151. css += '\n';
  152. }
  153. css = css.trim();
  154. css += '\n}\n';
  155. await fsp.writeFile(join(__dirname, '../../public/love.css'), css);
  156. }
  157. if (require.main === module) {
  158. void main();
  159. }