eleventy.config.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. module.exports = function(eleventyConfig) {
  2. const fs = require('fs');
  3. const path = require('path');
  4. const exifParser = require("exif-parser");
  5. // add my css file from the root folder
  6. eleventyConfig.addPassthroughCopy("bundle.css");
  7. eleventyConfig.addPassthroughCopy("img");
  8. eleventyConfig.addPassthroughCopy({ "_data/images": "photos" });
  9. // This line was to make sure my post.md weren't processed as Liquid,
  10. // permitting this post here
  11. eleventyConfig.setTemplateFormats(["md", "njk", "html"]);
  12. eleventyConfig.addGlobalData("site.author", "unakt");
  13. // Double with the .eleventyignore file, but just in case
  14. eleventyConfig.ignores.add("/_drafts/**");
  15. eleventyConfig.ignores.add("/README.md");
  16. eleventyConfig.addLayoutAlias("post", "post.njk");
  17. eleventyConfig.addCollection("postlist", function(collectionApi) {
  18. return collectionApi.getFilteredByGlob("./posts/*.md");
  19. });
  20. // Custom collection for mini images
  21. // It scans the ./src/_data/images/ folder for jpg files
  22. // and groups them by their parent folder name
  23. // Each image object contains its path, album name, and last modified date
  24. // ========================================================
  25. eleventyConfig.addCollection("miniImages", function(collectionApi) {
  26. const files = [];
  27. const baseDir = "./_data/images/";
  28. // Recursive function to find all jpgs
  29. const getFiles = (dir) => {
  30. if (!fs.existsSync(dir)) return; // [EXIF] Safety check
  31. fs.readdirSync(dir).forEach(file => {
  32. const fullPath = path.join(dir, file);
  33. if (fs.statSync(fullPath).isDirectory()) {
  34. getFiles(fullPath);
  35. } else if (file.endsWith(".jpg") ||
  36. file.endsWith(".jpeg") ||
  37. file.endsWith(".png") ||
  38. file.endsWith(".gif") ||
  39. file.endsWith(".webp")) {
  40. // .jpg an others extensions might be case sensitive on some systems !!
  41. // READ EXIF DATA
  42. let exifData = {};
  43. try {
  44. const buffer = fs.readFileSync(fullPath);
  45. const parser = exifParser.create(buffer);
  46. const result = parser.parse();
  47. exifData = {
  48. model: result.tags.Model || "Unknown",
  49. lens: result.tags.LensModel || "Unknown",
  50. focalLength: result.tags.FocalLength ? `${result.tags.FocalLength}` : "N/A",
  51. fNumber: result.tags.FNumber ? `f/${result.tags.FNumber}` : "N/A",
  52. exposure: result.tags.ExposureTime ? `1/${Math.round(1/result.tags.ExposureTime)}s` : "N/A",
  53. iso: result.tags.ISO || "N/A"
  54. };
  55. } catch (e) {
  56. console.error(`Could not parse EXIF for ${file}:`, e.message);
  57. }
  58. // END READ EXIF DATA
  59. // BEFORE =============
  60. const relativePath = path.relative("./_data/images", fullPath).replace(/\\/g, "/");
  61. //const pathParts = relativePath.split(path.sep).slice(0, -1); // Make Breadcrumb
  62. // ====================
  63. files.push({
  64. fullPath: fullPath, // We need this for the calculation below
  65. //webPath: fullPath.replace("src/", "/"),
  66. date: fs.statSync(fullPath).mtime,
  67. path: "/photos/" + relativePath,
  68. folderPath: path.relative(baseDir, path.dirname(fullPath)),
  69. exif: exifData,
  70. });
  71. }
  72. });
  73. };
  74. getFiles(baseDir);
  75. // Group them by album name
  76. const grouped = {};
  77. files.forEach(f => {
  78. const relFolder = path.relative(baseDir, path.dirname(f.fullPath));
  79. if (!grouped[relFolder]) {
  80. grouped[relFolder] = {
  81. images: [],
  82. subfolders: [],
  83. breadcrumbArray: relFolder === "" ? [] : relFolder.split(path.sep)
  84. //path: folderPath.split(path.sep) // Normalize to forward slashes
  85. };
  86. }
  87. grouped[relFolder].images.push(f);
  88. });
  89. // Second pass to link parents to children subfolders
  90. for (const parentPath in grouped) {
  91. for (const potentialChild in grouped) {
  92. const parentParts = parentPath === "" ? [] : parentPath.split(path.sep);
  93. const childParts = potentialChild.split(path.sep);
  94. // Is the child exactly one level deeper than the parent?
  95. if (potentialChild.startsWith(parentPath) &&
  96. childParts.length === parentParts.length + 1 &&
  97. parentPath !== potentialChild) {
  98. grouped[parentPath].subfolders.push(potentialChild);
  99. }
  100. }
  101. }
  102. return grouped;
  103. });
  104. // ========================================================
  105. eleventyConfig.addCollection("allPhotos", function(collectionApi) {
  106. //const grouped = collectionApi.getFilteredByTag("miniImages"); // This won't work since miniImages isn't a tag
  107. // Instead, use the logic we already built:
  108. const miniImages = collectionApi.getAll()[0].data.collections.miniImages;
  109. return Object.values(miniImages).flatMap(album => album.images);
  110. });
  111. // Date filter to format dates as YYYY-MM-DD
  112. //eleventyConfig.addFilter("date", function(dateObj, format = "YYYY-MM-DD") {
  113. // const d = new Date(dateObj);
  114. // return d.toISOString().split('T')[0]; // Returns YYYY-MM-DD
  115. // });
  116. eleventyConfig.addFilter("date", function(dateObj) {
  117. const d = new Date(dateObj);
  118. // Check if the date is actually valid
  119. if (isNaN(d.getTime())) {
  120. console.warn("Skipping invalid date for a file. Value received:", dateObj);
  121. return "Date Unknown";
  122. }
  123. return d.toISOString().split('T')[0];
  124. });
  125. return {
  126. // Ok idk this prevent markdown from being processed?
  127. markdownTemplateEngine: false,
  128. dir: {
  129. input: "./",
  130. output: "_site",
  131. layouts: "layouts",
  132. includes: "includes"
  133. }
  134. };
  135. };