From 299084de93ef8efa828d3fd082be898a8a8091dd Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Mon, 18 Sep 2023 02:16:53 +0100 Subject: [PATCH] =?UTF-8?q?Gatsby=20=E2=86=92=20Astro=20(#829)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * basic astro setup, kick out all gatsby configs * move content folder * src/pages setup * more file reorg * more config updates * more reorgs * refactor * refactor * bump astro * refactor * svg icon build system, theme switch * remark plugin for lead paragraph, more refactor * make images work * post meta * custom Picture component * Pagination, More component, 404 fixes * linking fixes * add table of contents * post actions fixes * tag fixes * content changes * content changes: move media files to their posts * more content moving, remove media folder * refactor remark-lead-paragraph * link css file when defined in post frontmatter * move content up again * kbd post update * allow js * downloads solution * add astro check * redirect_from solution * githubLink solution * reorg * exif solution as prebuild step * exif solution on each post during build * isolate lead paragraph extraction to articles * restore Exif components * deploy script update * fix redirects * xml & json feeds * build fix * fix exif readout in production * head and seo tweaks, add feeds * tweak image display * archive pages with single layout * restore tags archive * sitemap setup * restore thanks page functionality * reorg * cleanup * parallel scripts during prebuild * restore jest setup * remove jest, switch to vitest as test runner * adapt CI * test refactor * typescript tweaks * avatar fixes * typings * restore search functionality * theme switch with nanostores * fixes * test fixes * restore changelog functionality * umami script * border color tweak * related posts with fuse.js * plawright e2e testing setup * search tweaks * simplify typekit loading * photo fix * e2e tests * related posts fix * fix tags archive * tweaks * tweaks * linux snapshots * fix header test * new symlink tactic * fix dev server in codespaces * fix yaml * ci fixes * changelog loading tweaks * e2e against dev server on ci * changelog tweaks * ci tweaks * ci tweaks * ci tweaks * docs updates * ci tweaks * refactor photo creation script * package updates * refactor search * ci tweak * ci tweaks * test tweaks, more unit tests * more unit tests * post creation script tweaks * refactor new scripts, test them for real life * more tests * refactor * codeclimate-action update * uses update * limit ci runs * fix theme toggle, test it * more tests * favicon files cleanup * icon components location change * type checking through ci * command fixes * ci fix * search tweaks * ci tweaks * revised favicons, write post draft about it * drafts filtering fix * lint fix, favicon fixes * copy changes * fix related search images * content updates * new codeblock styles, copy tweaks, fixes * package updates * typing fixes * lint fix * content updates * restore link posts * faster theme switching * split up astro utils * related posts fixes * fix * refactor * fixes * copy tweaks * fixes * picture tweaks * image fixes * feed fixes, adapt for json feed v1.1 * e2e test updates * layout tweaks * update snaphots * migrate to createMarkdownProcessor * ci cache tweaks * activate more browsers for e2e testing * switch to macos-13 images * build caching tweaks * markdown fix * set image quality * remove avif generation * picture tweaks * head fixes * add og:image:alt * create-icons test * new post: Favicon Generation with Astro --- .../.markdownlint.json | 0 .stylelintrc => .config/.stylelintrc.json | 0 .config/astro.config.ts | 55 + .config/aws_redirects.xml | 74 + config.ts => .config/blog.config.ts | 10 +- .env.sample | 12 +- .eslintrc => .eslintrc.json | 33 +- .github/workflows/ci.yml | 149 +- .github/workflows/codeql-analysis.yml | 2 +- .gitignore | 22 +- .jest/__fixtures__/avatar.json | 22 - .jest/__fixtures__/github.json | 219 - .jest/__fixtures__/home.json | 523 - .jest/__fixtures__/link.json | 25 - .jest/__fixtures__/meta.json | 43 - .jest/__fixtures__/photos.json | 62 - .jest/__fixtures__/post.json | 41 - .jest/__fixtures__/postWithMore.json | 41 - .jest/__fixtures__/posts.json | 356 - .jest/__mocks__/file.js | 1 - .jest/__mocks__/gatsby.js | 29 - .jest/__mocks__/matchMedia.ts | 27 - .jest/__mocks__/svgr.js | 6 - .jest/__mocks__/wagmi.js | 72 - .jest/babel.config.js | 4 - .jest/jest.config.js | 58 - .jest/loadershim.js | 3 - .jest/setup-test-env.ts | 23 - .jest/testRender.ts | 12 - .prettierrc | 18 - .prettierrc.json | 14 + README.md | 161 +- _aws/redirects.xml | 70 - content/_schemas.ts | 71 + .../index.md} | 0 .../canon1.png | Bin .../canon2.png | Bin .../canon3.png | Bin .../canon4.png | Bin .../canoscanlide500f.jpg | Bin .../index.md} | 10 +- .../index.md} | 0 .../index.md} | 0 .../index.md} | 4 +- .../parallax.png | Bin .../Teaser-Aperture-File-Types.jpg | Bin .../aperturefiletypes_by_kremalicious.zip | Bin .../index.md} | 6 +- .../index.md} | 4 +- .../pulitzer.png | Bin .../PS_CR2FileIcon.png | Bin .../aperturefiletypes.png | Bin .../index.md} | 22 +- .../openwithpreview.png | Bin .../pathphotoshop.png | Bin .../pathpreview.png | Bin .../raw.png | Bin .../apassis.png | Bin .../index.md} | 6 +- .../index.md} | 6 +- .../webkit.png | Bin .../css.png | Bin .../index.md} | 48 +- .../navbar-kremalicious.png | Bin .../text-shadow-1.png | Bin .../text-shadow-10.png | Bin .../text-shadow-11.png | Bin .../text-shadow-12.png | Bin .../text-shadow-13.png | Bin .../text-shadow-14.png | Bin .../text-shadow-15.png | Bin .../text-shadow-2.png | Bin .../text-shadow-3.png | Bin .../text-shadow-4.png | Bin .../text-shadow-5.png | Bin .../text-shadow-6.png | Bin .../text-shadow-7.png | Bin .../text-shadow-8.png | Bin .../text-shadow-9.png | Bin .../text-shadow-hack.png | Bin .../textshadow-apple.png | Bin ...4-22-apple-releases-sdk-for-aperture-21.md | 17 - .../aperture97.png | Bin .../index.md | 19 + .../index.md} | 4 +- .../webkit.png | Bin 0 -> 36541 bytes .../aperturescan.png | Bin .../canondrivercontents.png | Bin .../canoscanlide500f.jpg | Bin 0 -> 58689 bytes .../index.md} | 14 +- .../scangear16bit.png | Bin .../scangear48bit.png | Bin .../scangear_color.png | Bin .../scangearwindow.png | Bin .../scanwindow_preview.png | Bin ...can-images-directly-into-apple-aperture.md | 38 - .../apertureimport_automatic.png | Bin .../apertureimport_automator.png | Bin .../apertureimportplugin.png | Bin .../aperturescan.png | Bin 0 -> 30914 bytes .../automator.png | Bin .../index.md | 42 + .../index.md} | 34 +- .../watermark_1.png | Bin .../watermark_2.png | Bin .../watermark_3.png | Bin .../watermark_4.png | Bin .../watermark_5.png | Bin .../watermark_6.png | Bin .../watermark_7.png | Bin .../watermark_8.png | Bin .../watermark_9.png | Bin .../watermark_aperture.jpg | Bin .../watermark_example_by_kremalicious.zip | Bin .../watermarkexample_final.jpg | Bin .../watermarkexample_v2.jpg | Bin .../watermarkexample_v3.jpg | Bin .../watermarkexample_v4.jpg | Bin .../index.md} | 4 +- .../viveza.png | Bin .../aperture15_1.png | Bin .../aperture15_10.png | Bin .../aperture15_11.png | Bin .../aperture15_12.png | Bin .../aperture15_13.png | Bin .../aperture15_14.jpg | Bin .../aperture15_15.png | Bin .../aperture15_2.png | Bin .../aperture15_3.png | Bin .../aperture15_4.png | Bin .../aperture15_5.png | Bin .../aperture15_6.png | Bin .../aperture15_7.png | Bin .../aperture15_8.jpg | Bin .../aperture15_8.png | Bin .../index.md} | 34 +- .../raw20.png | Bin .../index.md} | 6 +- .../indianajones_dock.png | Bin .../indianajones_first.png | Bin .../index.md} | 0 .../aperture97.png | Bin 0 -> 17737 bytes .../apertureedit_interface.jpg | Bin .../creaceed_hydra.png | Bin .../dft-light_ui.jpg | Bin .../dft-ozone_ui.jpg | Bin .../dft-powerstroke_uis.jpg | Bin .../dpmatte_index1.jpg | Bin .../imagestrends_shieoff.jpg | Bin .../imagetrends_hemi_10.jpg | Bin .../imagetrends_pearlywhite.png | Bin .../index.md} | 32 +- .../lensfix_ci.png | Bin .../noiseninja.png | Bin .../tiffen_aperture.jpg | Bin .../viveza_aperture_ui.jpg | Bin .../imagetrends_hemi_10.jpg | Bin 0 -> 167841 bytes .../index.md} | 6 +- .../index.md} | 6 +- .../parallax_illusion_css.png | Bin .../index.md} | 36 +- .../parallax-visualization.png | Bin .../parallax-visualization_big.png | Bin .../parallax_001.jpg | Bin .../parallax_002.jpg | Bin .../parallax_003.jpg | Bin .../parallax_004.jpg | Bin .../parallax_005.jpg | Bin .../parallax_006.jpg | Bin .../parallax_007.jpg | Bin .../parallax_008.jpg | Bin .../parallax_009.jpg | Bin .../parallax_010.jpg | Bin .../parallax_011.jpg | Bin .../parallax_012.jpg | Bin .../parallax_013.jpg | Bin .../parallax_014.png | Bin .../parallax_015.png | Bin .../parallax_016.jpg | Bin .../parallax_017.jpg | Bin .../apertureedit_logo.png | Bin .../index.md} | 6 +- content/articles/2008-06-01-chives.md | 23 - .../2008-06-01-chives}/Teaser-Chives.jpg | Bin .../chives_by_kremalicious.zip | Bin content/articles/2008-06-01-chives/index.md | 23 + .../index.md} | 4 +- .../twitter-bird-kremalicious.png | Bin .../twitter.png | Bin .../Teaser-Camera-Obscura-Icons.jpg | Bin .../View-from-the-Window-at-Le-Gras.png | Bin .../cameraobscura11_all.png | Bin .../cameraobscura_inuse.png | Bin .../coffee-cup-empty.png | Bin .../index.md} | 18 +- .../nicephore-niepce.jpg | Bin ...niepces_camera_obscura_by_kremalicious.zip | Bin ...the_window_at_le_gras_nicephore_niepce.jpg | Bin .../Teaser-Camera-Obscura-Walls.jpg | Bin .../index.md} | 6 +- ...obscura_wallpaper_pack_by_kremalicious.zip | Bin .../index.md} | 14 +- .../safari-logo.png | Bin .../safari4_zoom.png | Bin .../safari_4_tabs.png | Bin .../webinspector_2.png | Bin .../webinspector_3.png | Bin .../aperture128.png | Bin .../aperture_bt.png | Bin .../index.md} | 6 +- .../bonjour97.png | Bin .../coffee-cup-empty.png | Bin 0 -> 19496 bytes .../index.md} | 52 +- .../netatalk.png | Bin .../server_displays_by_kremalicious.zip | Bin .../serverdisplays.jpg | Bin .../timemachine97.png | Bin .../timemachinedisk97.png | Bin .../tm-sparsebundle.png | Bin .../ubuntu_mac_feature.jpg | Bin .../ubuntuserver1.png | Bin .../ubuntuserver2.png | Bin .../ubuntuserver3.png | Bin .../ubuntuserver4.png | Bin .../ubuntuserver4a.png | Bin .../ubuntuserver5.png | Bin .../ubuntuserver97.png | Bin .../apertureedit_logo2.png | Bin .../index.md} | 6 +- ...25-new-canon-stuff-xs-eos-1000-430ex-ii.md | 17 - .../canon1000d.png | Bin .../index.md | 19 + .../speedlite430exii.jpg | Bin ...ack-to-normal-on-kremaliciouscom-almost.md | 47 - .../aperture-plugin128.png | Bin .../index.md} | 8 +- .../jade_ui.png | Bin .../ptlens_ui.png | Bin .../index.md} | 8 +- .../kremalicious-iconiphone.png | Bin .../kremaliciousiphone.png | Bin ...e-plug-in-nik-announces-silver-efex-pro.md | 19 - .../aperture-plugin128.png | Bin 0 -> 18073 bytes .../index.md | 21 + .../nik_silverefex.png | Bin .../index.md} | 8 +- .../wordpress-logo.png | Bin .../index.md} | 4 +- .../jingjing_chacha_kremalicious.jpg | Bin .../index.md} | 14 +- .../niepces_aperture_vault256.png | Bin .../securevault1.png | Bin .../securevault2.png | Bin .../securevault3.png | Bin .../securevault4.png | Bin .../securevault5.png | Bin .../aperture-plugin128.png | Bin 0 -> 18073 bytes .../index.md} | 8 +- .../index.md} | 26 +- .../marsedit_kremalicious.png | Bin .../marsedit_kremalicious.txt | 0 .../marsedit_kremalicious_big.png | Bin .../Teaser-Icy-Box.jpg | Bin .../2008-08-26-icy-box-icons/icybox.jpg} | Bin .../icybox_by_kremalicious.zip | Bin .../index.md} | 8 +- .../architect-icon.jpg | Bin .../architect-ui.png | Bin .../index.md} | 8 +- .../magnifique-ui.png | Bin ...-08-28-canon-eos-50d-new-lens-announced.md | 27 - .../efs_18-200.png | Bin .../eos_50D_back.png | Bin .../eos_50D_front.png | Bin .../index.md | 31 + .../chrome-ui.png | Bin .../googlechrome.png | Bin .../index.md} | 17 +- .../Teaser-Mars-U.jpg | Bin .../index.md} | 7 +- .../mars-u-wall-by-kremalicious.zip | Bin .../Teaser-Coffee-Cup-Icon.jpg | Bin .../coffee_cup_by_kremalicious.zip | Bin .../index.md} | 6 +- .../Teaser-Coffee-Cup-Icon.jpg | Bin 0 -> 82023 bytes .../coffee-showcase-apple.png | Bin .../coffee-showcase-baumann.png | Bin .../coffee-showcase-benedik.png | Bin .../coffee-showcase-brasgalla.png | Bin .../coffee-showcase-brasgalla2.png | Bin .../coffee-showcase-cappuccinosofa.png | Bin .../coffee-showcase-england.png | Bin .../coffee-showcase-flarup.png | Bin .../coffee-showcase-jaeppinen.png | Bin .../coffee-showcase-kaycaffeine.png | Bin .../coffee-showcase-kretschmann.png | Bin .../coffee-showcase-lanham.png | Bin .../coffee-showcase-lopezruiz.png | Bin .../coffee-showcase-lovecappu.png | Bin .../coffee-showcase-macrabbit.png | Bin .../coffee-showcase-matu.png | Bin .../coffee-showcase-rask1.png | Bin .../coffee-showcase-rask2.png | Bin .../coffee-showcase-susumo.png | Bin .../coffee-showcase-times.png | Bin .../coffee-showcase-tut-abduzeedo.png | Bin .../coffee-showcase-tut-houle.png | Bin .../coffee-showcase-tut-psdtuts.png | Bin .../coffee-showcase-tut-vectuts.png | Bin .../coffee-showcase-vegrafik.png | Bin .../coffee-showcase-visualpharm.png | Bin .../index.md} | 54 +- .../aperture-impression.png | Bin .../aperture_borderfx.png | Bin .../aperture_bt.png | Bin 0 -> 80701 bytes .../index.md} | 20 +- .../watermark_5.png | Bin 0 -> 658866 bytes .../watermark_8.png | Bin 0 -> 13417 bytes .../watermark_aperture.jpg | Bin 0 -> 155262 bytes .../custom-gravatar.jpg | Bin .../index.md} | 7 +- .../index.md} | 5 +- .../futurama-mac-01.png | Bin .../futurama-mac-02.png | Bin .../futurama-mac-03.png | Bin .../futurama-mac-04.png | Bin .../futurama-mac-05.png | Bin .../futurama-mac-06.png | Bin .../futurama-mac-07.png | Bin .../futurama-mac-08.png | Bin .../futurama-mac-09.png | Bin .../futurama-mac-10.png | Bin .../futurama-mac-11.png | Bin .../futurama-mac-12.png | Bin .../futurama-mac-13.png | Bin .../futurama-mac-14.png | Bin .../futurama-mac-15.png | Bin .../futurama-mac-16.png | Bin .../futurama-mac-17.png | Bin .../futurama-mac-18.png | Bin .../futurama-mac-19.png | Bin .../futurama-mac-20.png | Bin .../futurama-mac-21.png | Bin .../futurama-mac-teaser.png | Bin .../futurama_gedeon.png | Bin .../futurama_hawkins1.png | Bin .../futurama_hawkins2.png | Bin .../futurama_kremalicious.png | Bin .../futurama_rawpixels.png | Bin .../index.md} | 105 +- .../out_of_whale_oil_detail.png | Bin .../index.md} | 16 +- .../vcardsite-arefjdey.png | Bin .../vcardsite-laurent.png | Bin .../vcardsite-maximilian.png | Bin .../vcardsite-mk.png | Bin .../vcardsite-rogie.png | Bin .../vcardsite-tim.png | Bin .../Teaser-Out-Of-Whale-Oil.jpg | Bin .../index.md} | 10 +- .../out-of-whale-oil-overview.png | Bin .../out-of-whale-oil-wall-by-kremalicious.zip | Bin .../out_of_whale_oil_detail.png | Bin 0 -> 45722 bytes .../coda-clips-icon-files.zip | Bin .../codaclips-hud.png | Bin .../codaclips-icon128.png | Bin .../codaclips-placeholder.png | Bin .../codaclips-teaser.png | Bin .../coffee-cup-icon-kremalicious.png | Bin .../index.md} | 42 +- .../share-link-bonanza-coda-clips.zip | Bin .../share-link-bonanza-html.zip | Bin .../tutorial-icon.png | Bin .../Teaser-Twitter-Crisp.jpg | Bin .../index.md} | 10 +- .../twitter-crisp-by-kremalicious.zip | Bin .../Adiumeetie-Dock-Preview.png | Bin .../Adiumeetie-Teaser-AdiumIcon.png | Bin .../Adiumeetie-Teaser.jpg | Bin .../Teaser-Adiumeetie.jpg | Bin .../adiumeetie-by-kremalicious.zip | Bin .../index.md} | 12 +- .../Teaser-Delibar-Icons.jpg | Bin .../delibar-by-kremalicious.zip | Bin .../index.md} | 8 +- .../index.md} | 39 +- .../wordpress-thumbnail-1.png | Bin .../wordpress-thumbnail-2.png | Bin .../wordpress-thumbnail-3.png | Bin .../wordpress-thumbnail-4.png | Bin .../wordpress-thumbnail-5.png | Bin .../Teaser-iPixelPad.png | Bin .../iPixelPad-Teaser-kremalicious2.jpg | Bin .../iPixelPad-Teaser1.png | Bin .../index.md} | 12 +- .../ipixelpad-homescreen-zoom.png | Bin .../ipixelpad_by_kremalicious.zip | Bin .../MomCorp-Walls-Overview.png | Bin .../Teaser-MomCorp-Wall.png | Bin .../index.md} | 8 +- .../momcorp_wall_by_kremalicious.zip | Bin .../Badged-Teaser-kremalicious.png} | Bin .../2011-12-15-badged}/badged-settings.png | Bin .../index.md} | 4 +- .../index.md} | 22 +- .../2012-02-26-mk-v2}/mkv2-android-chrome.png | Bin .../mkv2-android-firefox.png | Bin .../2012-02-26-mk-v2}/mkv2-android.png | Bin .../2012-02-26-mk-v2}/mkv2-balls.jpg | Bin .../2012-02-26-mk-v2}/mkv2-detail.png | Bin .../mkv2-ipad-touchindicator.jpg | Bin .../2012-02-26-mk-v2}/mkv2-ipad.png | Bin .../2012-02-26-mk-v2}/mkv2-iphone.png | Bin .../mkv2-portfolio-overlay.jpg | Bin .../mkv2-responsivelayouts.jpg | Bin .../2012-02-26-mk-v2}/mkv2-teaser-450x250.jpg | Bin .../2012-02-26-mk-v2}/mkv2-teaser-500x277.jpg | Bin .../2012-02-26-mk-v2}/mkv2-teaser-540x288.jpg | Bin .../2012-02-26-mk-v2}/mkv2.jpg | Bin .../Instagram-Swipe.png | Bin .../android-galaxy-note.png | Bin .../android-navigation-buttons.png | Bin .../index.md} | 8 +- .../tabs_overview.png | Bin .../index.md} | 16 +- .../kremalicious2-photogrid.jpg | Bin .../kremalicious2-photoposts.jpg | Bin .../kremalicious2-teaser.jpg | Bin .../kremalicious2-topicicons.jpg | Bin .../kremalicious2-typography.jpg | Bin .../kremaliciouscom-iPad-3.jpg | Bin .../WordPress-Admin-Icons-Template-Filled.png | Bin .../index.md} | 4 +- .../kremalicious-Teaser-WP-Icon-Template.png | Bin .../index.md} | 4 +- .../kremalicious-Teaser-WP-Icon-Template.png | Bin 0 -> 16436 bytes .../wp34_retina_icons.png | Bin ...ows-8-Metro-tile-kremalicious-all-apps.png | Bin ...ws-8-Metro-tile-kremalicious-in-action.png | Bin .../Windows-8-Metro-tile-kremalicious.png | Bin .../index.md} | 8 +- .../kremalicious-Teaser-Metro-Tile.jpg | Bin .../Google Android License.txt | 18 - .../Roboto-Regular-webfont.eot | Bin 26220 -> 0 bytes .../Roboto-Regular-webfont.svg | 147 - .../Roboto-Regular-webfont.ttf | Bin 26024 -> 0 bytes .../Roboto-Regular-webfont.woff | Bin 15280 -> 0 bytes .../_post-kbd.css | 93 + .../index.md | 4 +- .../post-kbd.css | 85 - .../Project-Purple-Dribbble.png | Bin .../Teaser-Project-Purple.png | Bin .../index.md} | 22 +- .../project-purple-ipad-kremalicious.png | Bin .../project-purple-iphone4-kremalicious.png | Bin .../project-purple-kremalicious.png | Bin .../project-purple-kremalicious.zip | Bin .../project-purple-nexus-kremalicious.png | Bin .../index.md} | 2 +- .../kremalicious-Teaser-ezeep.png | Bin .../buddha-colorscheme.png | Bin .../buddha-printer.png | Bin .../index.md} | 4 +- .../index.md} | 2 +- .../post-time.png | Bin .../index.md | 10 +- .../index.md} | 19 +- .../teaser-appstorebadges.png | Bin .../2017-05-16-hyper-mac-pro/index.md | 4 +- .../2018-11-01-gatsby-plugin-matomo/index.md | 6 +- .../index.md | 10 +- .../index.md | 30 +- .../index.md | 10 +- .../index.md | 36 +- content/articles/2020-05-08-uses/index.md | 47 +- .../2020-05-22-gatsby-redirect-from/index.md | 10 +- .../index.md | 18 +- .../favicon-generation-with-astro-teaser.png | Bin 0 -> 28371 bytes .../index.md | 223 + content/config.ts | 19 + content/media/Badged-Teaser-kremalicious.png | Bin 120471 -> 0 bytes content/media/Delibar-Icons-Teaser.jpg | Bin 72475 -> 0 bytes content/media/Delibar-Icons-Teaser2.png | Bin 117393 -> 0 bytes content/media/Twitter-Crisp-16.png | Bin 2823 -> 0 bytes content/media/adiumeetie-goodies-teaser.png | Bin 102557 -> 0 bytes content/media/aperture72.png | Bin 10914 -> 0 bytes content/media/box_download.png | Bin 4659 -> 0 bytes content/media/camera_obscura_wall_teaser.png | Bin 211867 -> 0 bytes content/media/cameraobscura11_all_thumb.png | Bin 66289 -> 0 bytes content/media/cameraobscura_aperture_128.png | Bin 23708 -> 0 bytes content/media/cameraobscura_teaser1.png | Bin 190628 -> 0 bytes .../ce2d29f40df411e2ad5812313817873b_7.jpg | Bin 125136 -> 0 bytes content/media/chives_wallpaper_teaser.png | Bin 198699 -> 0 bytes content/media/codaclips-icon48.png | Bin 4780 -> 0 bytes content/media/coffee-cup-icon-teaser.png | Bin 126610 -> 0 bytes content/media/delibar-website.png | Bin 191403 -> 0 bytes content/media/deliciouslinks.png | Bin 54288 -> 0 bytes content/media/diskimage98.png | Bin 8195 -> 0 bytes content/media/efs_18-200_thumb.png | Bin 38533 -> 0 bytes .../media/elegancesociale_smashingteaser.png | Bin 114110 -> 0 bytes content/media/encryption_certificate.png | Bin 5424 -> 0 bytes content/media/encryption_mail2.png | Bin 2163 -> 0 bytes content/media/eos_50D_back_thumb.png | Bin 54369 -> 0 bytes content/media/eos_50D_front_thumb.png | Bin 66488 -> 0 bytes content/media/filevault98.png | Bin 10373 -> 0 bytes content/media/firefox-icon.png | Bin 12899 -> 0 bytes content/media/firefox3promo.png | Bin 125692 -> 0 bytes content/media/free-pdf.png | Bin 18625 -> 0 bytes content/media/fry-2009-kremalicious.png | Bin 95945 -> 0 bytes content/media/hastuzeit-kremalicious2.jpg | Bin 12749 -> 0 bytes content/media/html-document-icon48.png | Bin 1261 -> 0 bytes content/media/icon-Facebook.png | Bin 2032 -> 0 bytes content/media/icon-Twitter2.png | Bin 2036 -> 0 bytes content/media/icon-deviantART.png | Bin 2042 -> 0 bytes content/media/icybox_teaser1.png | Bin 140684 -> 0 bytes content/media/icybox_teaser2_small.png | Bin 104793 -> 0 bytes content/media/jade_ui_thumb.jpg | Bin 49486 -> 0 bytes content/media/kremalicious-iconiphone-80.png | Bin 13905 -> 0 bytes content/media/kremalicious_nav.txt | 8 - content/media/kremaliciousiphone_thumb.png | Bin 34787 -> 0 bytes content/media/lens.png | Bin 19591 -> 0 bytes content/media/mars-u-teaser.png | Bin 177409 -> 0 bytes content/media/mediaMomCorpTeaser.png | Bin 32671 -> 0 bytes content/media/niepce_portrait.png | Bin 70748 -> 0 bytes content/media/nik_silverefex_thumb.png | Bin 64801 -> 0 bytes content/media/opera-icon.png | Bin 9275 -> 0 bytes content/media/paypal-logo.jpg | Bin 20190 -> 0 bytes content/media/ptlens_ui_thumb.jpg | Bin 52234 -> 0 bytes .../media/republica-banner-125x160_black.png | Bin 3122 -> 0 bytes .../media/republica10_kremaliciousbanner.png | Bin 6511 -> 0 bytes content/media/safari4_zoom_thumb.png | Bin 46725 -> 0 bytes content/media/snippet.png | Bin 15489 -> 0 bytes content/media/softwareupdate.png | Bin 15500 -> 0 bytes content/media/softwareupdate_photo200.png | Bin 46240 -> 0 bytes content/media/teaser-out-of-whale-oil.png | Bin 130290 -> 0 bytes content/media/teaser_elegance-sociale.png | Bin 109791 -> 0 bytes content/media/tweetie_select_bubbles.zip | Bin 49354 -> 0 bytes content/media/twitter-crisp-teaser.jpg | Bin 21739 -> 0 bytes content/media/twitter-crisp-teaser2.png | Bin 55593 -> 0 bytes content/media/webinspector_1.png | Bin 191717 -> 0 bytes content/media/xserve_screwed.png | Bin 81218 -> 0 bytes .../img_1820-Version-4.jpg | Bin .../index.md} | 2 +- .../index.md} | 2 +- .../schnecke_blatt.jpg | Bin .../MG_5885_2006-7-23.jpg | Bin .../index.md} | 2 +- .../floating-sky-1.jpg | Bin .../index.md} | 2 +- .../berliner_bruecke1-HDR-16bit.jpg | Bin .../index.md} | 2 +- .../index.md} | 2 +- ...muehle_suhlendorf_HDR_Tonemapped_16bit.jpg | Bin ...ramt_01_HDR_tonemapped_16bit-Version-2.jpg | Bin .../index.md} | 2 +- .../MG_9313_2007-02-10.jpg | Bin .../index.md} | 2 +- .../MG_1735-Version-2.jpg | Bin .../index.md} | 2 +- .../index.md} | 2 +- .../2008-06-30-stone-head}/stonehead.jpg | Bin .../2008-07-23-leaf-life}/MG_1920.jpg | Bin .../index.md} | 2 +- .../A-Long-Time-Ago.jpg | Bin .../index.md} | 2 +- .../2010-03-27-office-desk}/Office-Desk.jpg | Bin .../index.md} | 2 +- .../Typeface-condoms.jpg | Bin .../index.md} | 2 +- .../2010-08-07-bonsai}/Bonsai-5-Version-2.jpg | Bin .../index.md} | 2 +- .../GDR-Helvetica.jpg | Bin .../index.md} | 2 +- .../iPhone-Coasters-1-Version-2.jpg | Bin .../index.md} | 2 +- .../Basically-The-Monolith-Is-On-My-Desk.jpg | Bin .../index.md} | 2 +- .../Free-Monkey-Breath-Not-Soylent-Green.jpg | Bin .../index.md} | 2 +- .../Enjoying-Paper.jpg | Bin .../index.md} | 2 +- .../Glowing-Star-Inside.jpg | Bin .../index.md} | 2 +- .../Historic-Flood-Levels.jpg | Bin .../index.md} | 2 +- .../Broken-Nexus-S-Screen.jpg | Bin .../index.md} | 2 +- .../7f9397a265d811e1b9f1123138140926_7.jpg | Bin .../index.md} | 2 +- .../Blaue-Tuerme-1.jpg | Bin .../index.md} | 2 +- .../6313cc1e7db611e180c9123138016265_7.jpg | Bin .../index.md} | 2 +- .../de2ac24c7db911e1b9f1123138140926_7.jpg | Bin .../index.md} | 2 +- .../aff38e2c7f5311e1b10e123138105d6b_7.jpg | Bin .../index.md} | 2 +- content/photos/2012-04-07-buna.md | 5 - .../44af28f2805b11e18cf91231380fd29b_7.jpg | Bin content/photos/2012-04-07-buna/index.md | 5 + .../7838011c80ce11e19e4a12313813ffc0_7.jpg | Bin .../index.md} | 2 +- .../97a44d6080b711e181bd12313817987b_7.jpg | Bin .../index.md} | 2 +- .../5df6e0a280c911e1a87612313804ec91_7.jpg | Bin .../index.md} | 2 +- .../2ba6eeba81b111e1989612313815112c_7.jpg | Bin .../index.md} | 2 +- .../7e2b28f881b711e1af7612313813f8e8_7.jpg | Bin .../index.md} | 2 +- .../5fc688aa953811e180c9123138016265_7.jpg | Bin .../index.md} | 2 +- .../41b5a454a43811e1989612313815112c_7.jpg} | Bin .../index.md} | 2 +- .../690fe368a81911e1b2fe1231380205bf_7.jpg | Bin .../index.md} | 2 +- .../80a136dabff711e188131231381b5c25_7.jpg | Bin .../index.md} | 2 +- .../66a6e0c0d25a11e1a94522000a1e8aaf_7.jpg | Bin .../index.md} | 2 +- .../2ca7a094e10f11e1868c12313817a130_7.jpg | Bin .../index.md} | 2 +- .../c0c45b6eeea211e1ad8e22000a1cdbb8_7.jpg | Bin .../index.md} | 2 +- .../619b3900f92911e1a31922000a1cddf1_7.jpg | Bin .../index.md} | 2 +- .../84f9d2c4fb7411e19ca422000a1d0119_7.jpg | Bin .../index.md} | 2 +- .../01f8b0b8fcc611e19b5b123138140bce_7.jpg | Bin .../index.md} | 2 +- .../6c4003f2fe9911e1ae9122000a1e9e21_7.jpg | Bin .../index.md} | 2 +- .../8372983659_da0e88ca79_o.jpg | Bin .../index.md} | 2 +- .../8455835942_a9b9100373_o.jpg | Bin .../index.md} | 2 +- .../8450618380_83c64006c6_o.jpg | Bin .../index.md} | 2 +- .../8776417095_43553c88c2_o.jpg | Bin .../index.md} | 2 +- .../8782995066_e90ff6b3ae_o.jpg | Bin .../index.md} | 2 +- .../index.md} | 7 +- .../just-a-normal-sunday.jpg | Bin .../index.md} | 4 +- .../2014-03-15-potsdam}/potsdam.jpg | Bin .../index.md} | 2 +- .../typographic-diamond.jpg | Bin .../ai-wei-wei-stools.jpg | Bin .../index.md} | 2 +- .../airfield-reference-point.jpg | Bin .../index.md} | 2 +- ...anton-henning-heimat-schaffen-simpsons.jpg | Bin .../index.md} | 2 +- ...-thanks-for-the-tip-little-orange-blob.jpg | Bin .../index.md} | 2 +- .../index.md} | 2 +- .../most-surprising-dog-i-know.jpg | Bin .../index.md} | 2 +- ...obligatory-it-s-summer-in-berlin-photo.jpg | Bin ...hindu-temple-appears-around-the-corner.jpg | Bin .../index.md} | 2 +- .../Monstrum_Gameboy_Catherine_Kaleel.jpg | Bin .../index.md} | 2 +- .../index.md} | 2 +- .../tiny_tiny_demons.jpg | Bin .../index.md} | 4 +- .../sagrada-familia-ceiling.jpg | Bin .../index.md} | 2 +- .../streets-of-el-raval.jpg | Bin .../a-storm-is-coming.jpg | Bin .../index.md} | 4 +- .../index.md} | 2 +- .../keith-haring-vandalizing-a-wall.jpg | Bin .../index.md} | 2 +- .../streets-of-el-born.jpg | Bin .../index.md} | 2 +- .../new-passion-facade.jpg | Bin .../coolhaven-rotterdam.jpg | Bin .../index.md} | 4 +- .../behind-the-art.jpg | Bin .../index.md} | 4 +- .../2017-02-19-rotterdam-coats.jpg | Bin .../index.md} | 2 +- ...017-02-21-david-chipperfield-staircase.jpg | Bin .../index.md} | 2 +- .../2017-02-26-eu-gotham-city.jpg | Bin .../index.md} | 2 +- .../2017-02-27-amsterdam-cliche.jpg | Bin .../index.md} | 2 +- .../2017-02-27-its-dark-and-i-dont-exist.jpg | Bin .../index.md} | 2 +- .../2017-02-28-stedelijk-museum.jpg | Bin .../index.md} | 2 +- ...2017-02-28-temple-guardian-rijksmuseum.jpg | Bin .../index.md} | 2 +- .../2017-02-28-watching-the-night-watch.jpg | Bin .../index.md} | 2 +- .../2017-04-16-hamburgs-elbphilharmonie.jpg | Bin .../index.md} | 2 +- .../2017-04-29-palace-scaffolding.jpg | Bin .../index.md} | 2 +- ...17-07-05-kapaleeshwarar-temple-chennai.jpg | Bin .../index.md} | 2 +- ...-07-08-kochis-streetart-game-is-strong.jpg | Bin .../index.md} | 2 +- ...17-07-09-orphaned-elephant-with-friend.jpg | Bin .../index.md} | 2 +- .../2017-07-10-kochis-dhobhi-ghat.jpg | Bin .../index.md} | 2 +- ...7-07-13-mumbai-hand-painted-typography.jpg | Bin .../index.md} | 2 +- ...7-07-13-obligatory-gate-of-india-photo.jpg | Bin .../index.md} | 2 +- ...ati-shivaji-maharaj-vastu-sangrahalaya.jpg | Bin .../index.md} | 2 +- .../2017-11-10-acropolis-the-erechtheum.jpg | Bin .../index.md} | 2 +- .../2017-11-10-acropolis-the-parthenon.jpg | Bin .../index.md} | 2 +- .../2017-11-10-acropolis-the-propylaea.jpg | Bin .../index.md} | 2 +- ...15-el-born-centre-de-cultura-i-memoria.jpg | Bin .../index.md} | 2 +- .../2017-12-16-sagrada-familia.jpg | Bin .../index.md} | 2 +- .../2017-12-27-sao-paulo-traffic.jpg | Bin .../index.md} | 2 +- ...01-04-passagem-literaria-da-consolacao.jpg | Bin .../index.md} | 2 +- .../2018-01-05-samba-school.jpg | Bin .../index.md} | 2 +- .../2018-01-10-smoking-death.jpg | Bin .../index.md} | 2 +- .../2018-01-13-teatro-jaragua.jpg | Bin .../index.md} | 2 +- ...-15-a-revolucao-nao-sera-televisionada.jpg | Bin .../index.md} | 2 +- .../2018-01-15-fusca-e-pichacao.jpg | Bin .../index.md} | 2 +- .../2018-01-17-boa-viagem.jpg | Bin .../index.md} | 2 +- .../2018-01-17-instituto-ricardo-brennand.jpg | Bin .../index.md} | 2 +- .../2018-01-24-avenida-paulista-i.jpg | Bin .../index.md} | 2 +- .../2018-01-25-avenida-paulista-ii.jpg | Bin .../index.md} | 2 +- .../2018-01-26-auditorio-ibirapuera.jpg | Bin .../index.md} | 2 +- .../2018-01-26-oca-do-ibirapuera-i.jpg | Bin .../index.md} | 2 +- .../2018-01-26-oca-do-ibirapuera-ii.jpg | Bin .../index.md} | 2 +- ...1-26-pavilhao-das-culturas-brasileiras.jpg | Bin .../index.md} | 2 +- ...24-muzeul-national-de-arta-al-romaniei.jpg | Bin .../index.md} | 2 +- ...-muzeul-national-de-istorie-a-romaniei.jpg | Bin .../index.md} | 2 +- .../2018-05-01-may-day-kreuzberg.jpg | Bin .../index.md} | 2 +- .../2018-06-01-roger-waters-us-them.jpg | Bin .../index.md} | 2 +- .../2018-07-02-nine-inch-nails-zitadelle.jpg | Bin .../index.md} | 2 +- .../2018-09-01-stasi-museum.jpg | Bin .../index.md} | 2 +- .../2018-12-26-elevador-de-santa-justa.jpg | Bin .../index.md} | 2 +- .../2018-12-27-palacio-nacional-da-pena.jpg | Bin .../index.md} | 2 +- .../2018-12-27-rua-da-prata.jpg | Bin .../index.md} | 2 +- .../2018-12-29-gare-do-oriente.jpg | Bin .../index.md} | 2 +- .../2019-01-27-all-work-and-no-play.jpg | Bin .../index.md} | 2 +- .../2019-02-25-edificio-italia.jpg | Bin .../index.md} | 2 +- ...zilian-museum-of-sculpture-and-ecology.jpg | Bin .../index.md} | 2 +- .../2019-03-13-paraty-mirim.jpg | Bin .../index.md} | 2 +- ...2019-03-18-catedral-da-se-de-sao-paulo.jpg | Bin .../index.md} | 2 +- .../2019-08-18-german-chancellery-ii.jpg | Bin .../index.md} | 2 +- .../2019-09-28-vatican-museums.jpg | Bin .../index.md} | 2 +- .../2019-09-29-arco-di-costantino.jpg | Bin .../index.md} | 2 +- .../2019-09-29-foro-di-cesare.jpg | Bin .../index.md} | 2 +- .../2019-11-02-orszaghaz-i.jpg | Bin .../index.md} | 2 +- .../2019-11-03-orszaghaz-ii.jpg | Bin .../index.md} | 2 +- .../2019-11-03-orszaghaz-iii.jpg | Bin .../index.md} | 2 +- .../2019-11-16-helmut-newton-foundation.jpg | Bin .../index.md} | 2 +- .../2020-01-05-raw-gelande.jpg | Bin .../index.md} | 2 +- .../2020-01-17-balloon-dog.jpg | Bin .../index.md} | 2 +- .../2020-01-17-bremen-cathedral.jpg | Bin .../index.md} | 2 +- .../2020-06-14-x-marks-the-spot.jpg | Bin .../index.md} | 2 +- .../2020-06-28-lines-of-nature.jpg | Bin .../index.md} | 2 +- .../{ => 2020-08-13-2020}/2020-08-13-2020.jpg | Bin .../index.md} | 2 +- .../2020-08-16-castle-gardens.jpg | Bin .../index.md} | 2 +- .../2020-09-12-friedrichshain.jpg | Bin .../index.md} | 2 +- .../2020-10-11-charite.jpg | Bin .../index.md} | 2 +- .../2020-10-25-letters-change.jpg | Bin .../index.md} | 2 +- .../2020-11-29-wall-memorial.jpg | Bin .../index.md} | 2 +- .../2020-12-22-tier-pandemic.jpg | Bin .../index.md} | 2 +- .../2021-02-21-reflections.jpg | Bin .../index.md} | 2 +- .../2021-07-07-museum-neuruppin-staircase.jpg | Bin .../index.md} | 2 +- .../2021-08-05-maidan-nezalezhnosti.jpg | Bin .../index.md} | 2 +- ...mihayila-ta-ukrayinskih-novomuchenikiv.jpg | Bin .../index.md} | 2 +- .../2021-08-08-kyiv-funicular.jpg | Bin .../index.md} | 2 +- .../2021-08-08-kyiv-underground.jpg | Bin .../index.md} | 2 +- .../2021-08-09-kiyiv-pasazhirskij.jpg | Bin .../index.md} | 2 +- .../2021-08-17-horticya.jpg | Bin .../index.md} | 2 +- .../2021-08-17-zaporizhzhya.jpg | Bin .../index.md} | 2 +- .../2021-09-26-arc-de-triomphe-wrapped.jpg | Bin .../index.md} | 2 +- .../2021-09-26-centre-pompidou-pigeons.jpg | Bin .../index.md} | 2 +- .../2021-09-26-louvre-i.jpg | Bin .../index.md} | 2 +- .../2021-09-26-tour-eiffel.jpg | Bin .../index.md} | 2 +- .../2021-09-29-louvre-ii.jpg | Bin .../index.md} | 2 +- .../2021-09-30-tgv-euroduplex.jpg | Bin .../index.md} | 2 +- ...-04-santa-maria-la-real-de-la-almudena.jpg | Bin .../index.md} | 2 +- .../2021-10-09-ponte-da-arrabida.jpg | Bin .../index.md} | 2 +- .../2021-10-11-garagem.jpg | Bin .../index.md} | 2 +- .../2021-10-12-ponte-de-dom-luis-i.jpg | Bin .../index.md} | 2 +- .../2021-10-14-lince-iberico.jpg | Bin .../index.md} | 2 +- .../2021-10-16-gare-do-oriente-ii.jpg | Bin .../index.md} | 2 +- .../{ => 2021-10-17-maat}/2021-10-17-maat.jpg | Bin .../index.md} | 2 +- .../2021-10-17-padrao-dos-descobrimentos.jpg | Bin .../index.md} | 2 +- .../2021-10-17-ponte-25-de-abril.jpg | Bin .../index.md} | 2 +- .../2021-10-17-shiny-colonialism.jpg | Bin .../index.md} | 2 +- .../2021-10-23-santuario-de-cristo-rei.jpg | Bin .../index.md} | 2 +- .../2021-10-29-ponte-vasco-da-gama.jpg | Bin .../index.md} | 2 +- .../2021-10-31-sagrada-familia-ii.jpg | Bin .../index.md} | 2 +- .../2021-11-06-mae-d-agua.jpg | Bin .../index.md} | 2 +- .../2021-11-21-assembleia-da-republica.jpg | Bin .../index.md} | 2 +- .../2021-11-25-praca-do-comercio.jpg | Bin .../index.md} | 2 +- .../2021-11-26-forever-bicycles.jpg | Bin .../index.md} | 2 +- .../2021-11-26-law-of-the-journey.jpg | Bin .../index.md} | 2 +- gatsby-browser.tsx | 7 - gatsby-config.ts | 220 - gatsby-node.ts | 180 - gatsby-ssr.tsx | 26 - gatsby/algolia.ts | 89 - gatsby/createExif.ts | 148 - gatsby/createMarkdownFields.ts | 72 - gatsby/createPages.ts | 133 - gatsby/feeds.ts | 75 - gatsby/sources.ts | 63 - package-lock.json | 51935 ++-------------- package.json | 148 +- {static => public}/robots.txt | 2 +- {static => public}/sw.js | 0 scripts/create-icons/Props.d.ts | 320 + scripts/create-icons/index.test.ts | 39 + scripts/create-icons/index.ts | 103 + scripts/create-icons/svg.ts | 87 + scripts/create-symlinks.sh | 26 + scripts/deploy-s3.sh | 31 +- scripts/move-downloads.test.ts | 43 + scripts/move-downloads.ts | 73 + scripts/new.ts | 119 - scripts/new/createArticlePost.ts | 52 + scripts/new/createPhotoPost.ts | 77 + scripts/new/index.test.ts | 78 + scripts/new/index.ts | 26 + scripts/{ => new}/new-article.md | 2 +- scripts/{ => new}/new-photo.md | 5 +- scripts/redirect-from.test.ts | 32 + scripts/redirect-from.ts | 76 + src/@types/Image.d.ts | 7 - src/@types/Post.d.ts | 8 - src/@types/css.d.ts | 1 - .../{node_modules.d.ts => dmsdec/index.d.ts} | 5 - src/@types/global.d.ts | 9 - src/@types/node-iptc/index.d.ts | 71 + src/components/BackButton.astro | 24 + src/components/Changelog/index.astro | 50 + .../index.module.css} | 17 +- src/components/Copy.astro | 63 + src/components/{atoms => }/Divider.module.css | 2 +- src/components/Donation/Coin.astro | 42 + src/components/Donation/Web3.tsx | 15 + .../Web3Donation/Alert.module.css | 0 .../Web3Donation/Alert.test.tsx | 2 +- .../Web3Donation/Alert.tsx | 8 +- .../Web3Donation/Conversion.module.css | 4 +- .../Web3Donation/Conversion.test.tsx | 4 +- .../Web3Donation/Conversion.tsx | 30 +- .../Web3Donation/InputGroup.module.css | 4 +- .../Donation/Web3Donation/InputGroup.test.tsx | 39 + .../Web3Donation/InputGroup.tsx | 22 +- .../Web3Donation/index.module.css | 14 +- .../Donation/Web3Donation/index.test.tsx | 27 + .../Web3Donation/index.tsx | 31 +- src/components/Exif/ExifData.astro | 15 + src/components/Exif/ExifMap.test.tsx | 20 + src/components/Exif/ExifMap.tsx | 57 + src/components/Exif/index.astro | 47 + .../Exif.module.css => Exif/index.module.css} | 5 +- src/components/Footer/Networks.astro | 30 + .../{molecules => Footer}/Networks.module.css | 0 src/components/Footer/Vcard.astro | 28 + .../{molecules => Footer}/Vcard.module.css | 6 +- src/components/Footer/index.astro | 30 + .../index.module.css} | 0 src/components/Hamburger.astro | 84 + src/components/Header/index.astro | 21 + .../index.module.css} | 2 +- .../index.module.css} | 2 +- src/components/Input/index.test.tsx | 8 + .../{atoms/Input.tsx => Input/index.tsx} | 4 +- src/components/Layout.test.tsx | 7 - src/components/Layout.tsx | 20 - src/components/Menu/index.astro | 39 + .../Menu.module.css => Menu/index.module.css} | 5 +- src/components/More.astro | 42 + src/components/Pagination/PageNumber.astro | 18 + src/components/Pagination/PrevNext.astro | 19 + src/components/Pagination/index.astro | 25 + .../index.module.css} | 1 - src/components/PhotoTeaser.astro | 43 + src/components/Picture/index.astro | 105 + .../index.module.css} | 18 +- src/components/PostTeaser/index.astro | 38 + .../index.module.css} | 12 +- src/components/RelatedPosts/index.astro | 65 + .../index.module.css} | 14 +- .../Results/Empty.module.css} | 0 .../Results/Empty.tsx} | 16 +- .../Results/index.module.css} | 26 +- src/components/Search/Results/index.tsx | 49 + .../Search.module.css} | 12 + src/components/Search/Search.test.tsx | 64 + src/components/Search/Search.tsx | 97 + src/components/Search/index.astro | 50 + src/components/Tag.astro | 38 + src/components/ThemeSwitch/index.astro | 23 + .../index.module.css} | 4 + src/components/ThemeSwitch/theme.cjs | 74 + src/components/ThemeSwitch/theme.test.ts | 110 + src/components/Time.astro | 20 + src/components/Toc.astro | 29 + src/components/atoms/Changelog.test.tsx | 16 - src/components/atoms/Changelog.tsx | 88 - src/components/atoms/Copy.module.css | 29 - src/components/atoms/Copy.test.tsx | 10 - src/components/atoms/Copy.tsx | 21 - src/components/atoms/Exif.test.tsx | 24 - src/components/atoms/Exif.tsx | 58 - src/components/atoms/ExifMap.tsx | 45 - src/components/atoms/Hamburger.module.css | 70 - src/components/atoms/Hamburger.tsx | 23 - src/components/atoms/HeadMeta/SchemaOrg.tsx | 62 - src/components/atoms/HeadMeta/index.tsx | 72 - src/components/atoms/Icon.module.css | 10 - src/components/atoms/Icon.test.tsx | 21 - src/components/atoms/Icon.tsx | 69 - src/components/atoms/Image.tsx | 56 - src/components/atoms/Input.test.tsx | 8 - src/components/atoms/Tag.module.css | 20 - src/components/atoms/Tag.tsx | 22 - src/components/atoms/Time.tsx | 13 - src/components/atoms/Transitions.ts | 32 - src/components/atoms/Typekit.tsx | 17 - src/components/layouts/Archive.astro | 58 + src/components/layouts/Base/Head.astro | 119 + src/components/layouts/Base/SchemaOrg.astro | 51 + src/components/layouts/Base/index.astro | 35 + .../Base/index.module.css} | 41 +- src/components/layouts/Post/Action.astro | 57 + src/components/layouts/Post/Actions.astro | 46 + .../layouts/Post/Actions.module.css | 16 + src/components/layouts/Post/Date.astro | 25 + src/components/layouts/Post/LinkActions.astro | 20 + .../Post/LinkActions.module.css | 1 - src/components/layouts/Post/Meta.astro | 44 + .../Post/Meta.module.css | 0 src/components/layouts/Post/PrevNext.astro | 41 + .../Post/PrevNext.module.css | 0 src/components/layouts/Post/Title.astro | 36 + .../Post/Title.module.css | 5 +- src/components/layouts/Post/index.astro | 74 + src/components/layouts/Post/index.module.css | 66 + src/components/molecules/Menu.tsx | 39 - src/components/molecules/Networks.test.tsx | 15 - src/components/molecules/Networks.tsx | 39 - src/components/molecules/Pagination.tsx | 72 - src/components/molecules/PostDate.module.css | 6 - src/components/molecules/PostDate.tsx | 19 - src/components/molecules/PostTeaser.test.tsx | 20 - src/components/molecules/PostTeaser.tsx | 65 - .../molecules/RelatedPosts.test.tsx | 16 - src/components/molecules/RelatedPosts.tsx | 104 - .../molecules/Search/SearchButton.module.css | 22 - .../molecules/Search/SearchButton.tsx | 16 - .../molecules/Search/SearchInput.tsx | 34 - .../molecules/Search/SearchResults.tsx | 79 - .../molecules/Search/index.module.css | 46 - src/components/molecules/Search/index.tsx | 71 - src/components/molecules/ThemeSwitch.test.tsx | 20 - src/components/molecules/ThemeSwitch.tsx | 33 - src/components/molecules/Vcard.tsx | 53 - .../Web3Donation/InputGroup.test.tsx | 20 - src/components/organisms/Footer.test.tsx | 7 - src/components/organisms/Footer.tsx | 40 - src/components/organisms/Header.test.tsx | 19 - src/components/organisms/Header.tsx | 25 - src/components/templates/Archive.module.css | 14 - src/components/templates/Archive.test.tsx | 23 - src/components/templates/Archive.tsx | 71 - src/components/templates/Page.module.css | 9 - src/components/templates/Page.tsx | 19 - src/components/templates/Photos.module.css | 26 - src/components/templates/Photos.test.tsx | 24 - src/components/templates/Photos.tsx | 107 - .../templates/Post/Actions.module.css | 57 - src/components/templates/Post/Actions.tsx | 53 - .../templates/Post/Content.module.css | 11 - src/components/templates/Post/Content.tsx | 38 - src/components/templates/Post/Lead.module.css | 9 - src/components/templates/Post/Lead.tsx | 31 - src/components/templates/Post/LinkActions.tsx | 24 - src/components/templates/Post/Meta.tsx | 45 - src/components/templates/Post/More.module.css | 25 - src/components/templates/Post/More.tsx | 19 - src/components/templates/Post/PrevNext.tsx | 39 - src/components/templates/Post/Title.tsx | 40 - src/components/templates/Post/Toc.module.css | 15 - src/components/templates/Post/Toc.tsx | 18 - .../templates/Post/index.module.css | 17 - src/components/templates/Post/index.test.tsx | 31 - src/components/templates/Post/index.tsx | 161 - src/env.d.ts | 3 + src/helpers/umami.ts | 9 - src/helpers/wrapPageElement.test.tsx | 13 - src/helpers/wrapPageElement.tsx | 11 - src/hooks/useDarkMode.ts | 84 - src/hooks/useSiteMetadata.ts | 37 - src/images/apple-touch-icon.png | Bin 10894 -> 0 bytes src/images/favicon-16x16.png | Bin 819 -> 0 bytes src/images/favicon-32x32.png | Bin 1349 -> 0 bytes src/images/favicon-96x96.png | Bin 5039 -> 0 bytes src/images/favicon-mask.svg | 11 - src/images/favicon.png | Bin 0 -> 3706 bytes src/images/favicon.svg | 29 + src/images/kremalicious1024.png | Bin 263997 -> 0 bytes src/images/kremalicious512.png | Bin 87864 -> 0 bytes src/images/krlcus-cloud16.png | Bin 708 -> 0 bytes src/images/krlcus-cloud32.png | Bin 1608 -> 0 bytes src/images/logo-kremalicious-g-profile.png | Bin 66164 -> 0 bytes src/images/metro-tile.png | Bin 1751 -> 0 bytes src/images/touch-icon-192x192.png | Bin 18372 -> 0 bytes src/lib/astro/astro.test.ts | 75 + src/lib/astro/getAllPosts.ts | 14 + src/lib/astro/getAllPostsForSearch.ts | 36 + src/lib/astro/getAllTags.ts | 30 + src/lib/astro/getPostsByTag.ts | 9 + src/lib/astro/index.ts | 6 + src/lib/astro/loadAndFormatCollection.ts | 80 + src/lib/astro/sortPosts.ts | 14 + src/lib/exif/format.ts | 92 + src/lib/exif/index.ts | 35 + src/lib/exif/types.d.ts | 25 + src/lib/feed.test.ts | 34 + src/lib/feed.ts | 14 + src/lib/github.test.ts | 59 + src/lib/github.ts | 53 + src/lib/markdown.ts | 7 + src/{helpers => lib}/rainbowkit.ts | 18 +- src/lib/remark-lead-paragraph.test.ts | 52 + src/lib/remark-lead-paragraph.ts | 50 + src/lib/remark-toc.test.ts | 81 + src/lib/remark-toc.ts | 45 + src/lib/slugify.test.ts | 23 + src/lib/slugify.ts | 8 + src/lib/umami.test.ts | 36 + src/lib/umami.ts | 11 + src/pages/404.astro | 102 + src/pages/404.module.css | 82 - src/pages/404.tsx | 28 - src/pages/[...slug].astro | 33 + src/pages/__tests__/404.test.tsx | 13 - src/pages/__tests__/index.test.tsx | 12 - src/pages/__tests__/tags.test.tsx | 22 - src/pages/api/posts.ts | 7 + src/pages/archive/[page].astro | 22 + src/pages/archive/index.astro | 3 + src/pages/favicon.ico.ts | 15 + src/pages/feed.json.ts | 50 + src/pages/feed.xml.ts | 27 + src/pages/index.astro | 61 + src/pages/index.module.css | 46 - src/pages/index.tsx | 83 - src/pages/manifest.json.ts | 35 + src/pages/photos/[page].astro | 22 + src/pages/photos/index.astro | 3 + .../{styleguide/index.md => styleguide.md} | 6 +- src/pages/tags.module.css | 15 - src/pages/tags.tsx | 47 - src/pages/tags/[tag].astro | 38 + src/pages/tags/index.astro | 48 + src/pages/thanks.astro | 53 + src/pages/thanks.module.css | 67 - src/pages/thanks.tsx | 84 - src/stores/search.ts | 3 + src/{global => styles}/_alerts.css | 6 +- src/{global => styles}/_buttons.css | 4 +- src/{global => styles}/_code.css | 77 +- src/{global => styles}/_variables.css | 12 +- src/{global => styles}/global.css | 38 +- src/{global => styles}/imports.css | 0 static/apple-touch-icon.png | Bin 10894 -> 0 bytes static/favicon.ico | Bin 6518 -> 0 bytes test/__fixtures__/image-with-metadata.jpg | Bin 0 -> 281289 bytes test/__fixtures__/new-article.md | 11 + test/__fixtures__/new-photo.md | 12 + .../__mocks__/@rainbow-me/rainbowkit.js | 12 +- test/__mocks__/wagmi.ts | 105 + test/e2e/404.spec.ts | 15 + ...ches-screenshot-1-Mobile-Chrome-darwin.png | Bin 0 -> 22369 bytes ...tches-screenshot-1-Mobile-Chrome-linux.png | Bin 0 -> 21596 bytes ...ches-screenshot-1-Mobile-Safari-darwin.png | Bin 0 -> 26003 bytes ...tches-screenshot-1-Mobile-Safari-linux.png | Bin 0 -> 18802 bytes .../matches-screenshot-1-chromium-darwin.png | Bin 0 -> 29096 bytes .../matches-screenshot-1-chromium-linux.png | Bin 0 -> 28222 bytes .../matches-screenshot-1-firefox-darwin.png | Bin 0 -> 42839 bytes .../matches-screenshot-1-firefox-linux.png | Bin 0 -> 42771 bytes .../matches-screenshot-1-webkit-darwin.png | Bin 0 -> 42329 bytes .../matches-screenshot-1-webkit-linux.png | Bin 0 -> 24594 bytes test/e2e/header.spec.ts | 87 + ...ches-screenshot-1-Mobile-Chrome-darwin.png | Bin 0 -> 2307 bytes ...tches-screenshot-1-Mobile-Chrome-linux.png | Bin 0 -> 3594 bytes ...ches-screenshot-1-Mobile-Safari-darwin.png | Bin 0 -> 4068 bytes ...tches-screenshot-1-Mobile-Safari-linux.png | Bin 0 -> 3239 bytes .../matches-screenshot-1-chromium-darwin.png | Bin 0 -> 5412 bytes .../matches-screenshot-1-chromium-linux.png | Bin 0 -> 6726 bytes .../matches-screenshot-1-firefox-darwin.png | Bin 0 -> 6459 bytes .../matches-screenshot-1-firefox-linux.png | Bin 0 -> 6449 bytes .../matches-screenshot-1-webkit-darwin.png | Bin 0 -> 8541 bytes .../matches-screenshot-1-webkit-linux.png | Bin 0 -> 6316 bytes test/e2e/index.spec.ts | 35 + test/e2e/photos.spec.ts | 9 + test/e2e/post.spec.ts | 30 + test/e2e/thanks.spec.ts | 15 + test/playwright.config.ts | 56 + test/vitest.config.ts | 33 + test/vitest.setup.ts | 25 + tsconfig.json | 48 +- vendor/polar-0.0.6.vsix | Bin 955804 -> 0 bytes 1203 files changed, 12947 insertions(+), 54100 deletions(-) rename .markdownlint.json => .config/.markdownlint.json (100%) rename .stylelintrc => .config/.stylelintrc.json (100%) create mode 100644 .config/astro.config.ts create mode 100644 .config/aws_redirects.xml rename config.ts => .config/blog.config.ts (81%) rename .eslintrc => .eslintrc.json (50%) delete mode 100644 .jest/__fixtures__/avatar.json delete mode 100644 .jest/__fixtures__/github.json delete mode 100644 .jest/__fixtures__/home.json delete mode 100644 .jest/__fixtures__/link.json delete mode 100644 .jest/__fixtures__/meta.json delete mode 100644 .jest/__fixtures__/photos.json delete mode 100644 .jest/__fixtures__/post.json delete mode 100644 .jest/__fixtures__/postWithMore.json delete mode 100644 .jest/__fixtures__/posts.json delete mode 100644 .jest/__mocks__/file.js delete mode 100644 .jest/__mocks__/gatsby.js delete mode 100644 .jest/__mocks__/matchMedia.ts delete mode 100644 .jest/__mocks__/svgr.js delete mode 100644 .jest/__mocks__/wagmi.js delete mode 100644 .jest/babel.config.js delete mode 100644 .jest/jest.config.js delete mode 100644 .jest/loadershim.js delete mode 100644 .jest/setup-test-env.ts delete mode 100644 .jest/testRender.ts delete mode 100644 .prettierrc create mode 100644 .prettierrc.json delete mode 100644 _aws/redirects.xml create mode 100644 content/_schemas.ts rename content/articles/{2007-03-01-adjustment-tool-guide-for-aperture-152.md => 2007-03-01-adjustment-tool-guide-for-aperture-152/index.md} (100%) rename content/{media => articles/2007-06-11-finally-a-universal-scanner-driver-for-the-canon-canoscan-lide-500f-for-intel-macs}/canon1.png (100%) rename content/{media => articles/2007-06-11-finally-a-universal-scanner-driver-for-the-canon-canoscan-lide-500f-for-intel-macs}/canon2.png (100%) rename content/{media => articles/2007-06-11-finally-a-universal-scanner-driver-for-the-canon-canoscan-lide-500f-for-intel-macs}/canon3.png (100%) rename content/{media => articles/2007-06-11-finally-a-universal-scanner-driver-for-the-canon-canoscan-lide-500f-for-intel-macs}/canon4.png (100%) rename content/{media => articles/2007-06-11-finally-a-universal-scanner-driver-for-the-canon-canoscan-lide-500f-for-intel-macs}/canoscanlide500f.jpg (100%) rename content/articles/{2007-06-11-finally-a-universal-scanner-driver-for-the-canon-canoscan-lide-500f-for-intel-macs.md => 2007-06-11-finally-a-universal-scanner-driver-for-the-canon-canoscan-lide-500f-for-intel-macs/index.md} (91%) rename content/articles/{2008-02-26-how-to-quickly-generate-encrypted-logins-on-a-mac-for-htaccess-protected-sites.md => 2008-02-26-how-to-quickly-generate-encrypted-logins-on-a-mac-for-htaccess-protected-sites/index.md} (100%) rename content/articles/{2008-03-30-launch-of-kremaliciouscom.md => 2008-03-30-launch-of-kremaliciouscom/index.md} (100%) rename content/articles/{2008-03-31-love-the-parallax.md => 2008-03-31-love-the-parallax/index.md} (80%) rename content/{media => articles/2008-03-31-love-the-parallax}/parallax.png (100%) rename content/{media => articles/2008-04-04-aperture-file-types}/Teaser-Aperture-File-Types.jpg (100%) rename content/{media => articles/2008-04-04-aperture-file-types}/aperturefiletypes_by_kremalicious.zip (100%) rename content/articles/{2008-04-04-aperture-file-types.md => 2008-04-04-aperture-file-types/index.md} (80%) rename content/articles/{2008-04-08-pulitzer-price-winners-2008-announced-various-photographers-awarded.md => 2008-04-08-pulitzer-price-winners-2008-announced-various-photographers-awarded/index.md} (96%) rename content/{media => articles/2008-04-08-pulitzer-price-winners-2008-announced-various-photographers-awarded}/pulitzer.png (100%) rename content/{media => articles/2008-04-09-changing-the-image-icons-in-mac-os-x-leopard}/PS_CR2FileIcon.png (100%) rename content/{media => articles/2008-04-09-changing-the-image-icons-in-mac-os-x-leopard}/aperturefiletypes.png (100%) rename content/articles/{2008-04-09-changing-the-image-icons-in-mac-os-x-leopard.md => 2008-04-09-changing-the-image-icons-in-mac-os-x-leopard/index.md} (53%) rename content/{media => articles/2008-04-09-changing-the-image-icons-in-mac-os-x-leopard}/openwithpreview.png (100%) rename content/{media => articles/2008-04-09-changing-the-image-icons-in-mac-os-x-leopard}/pathphotoshop.png (100%) rename content/{media => articles/2008-04-09-changing-the-image-icons-in-mac-os-x-leopard}/pathpreview.png (100%) rename content/{media => articles/2008-04-09-changing-the-image-icons-in-mac-os-x-leopard}/raw.png (100%) rename content/{media => articles/2008-04-14-new-automation-helper-for-apples-aperture-released}/apassis.png (100%) rename content/articles/{2008-04-14-new-automation-helper-for-apples-aperture-released.md => 2008-04-14-new-automation-helper-for-apples-aperture-released/index.md} (72%) rename content/articles/{2008-04-15-webkit-team-introduced-css-based-gradients.md => 2008-04-15-webkit-team-introduced-css-based-gradients/index.md} (88%) rename content/{media => articles/2008-04-15-webkit-team-introduced-css-based-gradients}/webkit.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/css.png (100%) rename content/articles/{2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow.md => 2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow/index.md} (92%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/navbar-kremalicious.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-1.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-10.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-11.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-12.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-13.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-14.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-15.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-2.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-3.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-4.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-5.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-6.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-7.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-8.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-9.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/text-shadow-hack.png (100%) rename content/{media => articles/2008-04-17-make-cool-and-clever-text-effects-with-css-text-shadow}/textshadow-apple.png (100%) delete mode 100644 content/articles/2008-04-22-apple-releases-sdk-for-aperture-21.md rename content/{media => articles/2008-04-22-apple-releases-sdk-for-aperture-21}/aperture97.png (100%) create mode 100644 content/articles/2008-04-22-apple-releases-sdk-for-aperture-21/index.md rename content/articles/{2008-04-28-more-awesomeness-from-the-webkit-team-css-masks.md => 2008-04-28-more-awesomeness-from-the-webkit-team-css-masks/index.md} (58%) create mode 100644 content/articles/2008-04-28-more-awesomeness-from-the-webkit-team-css-masks/webkit.png rename content/{media => articles/2008-05-04-using-the-canoscan-lide-500f-with-mac-os-x-leopard}/aperturescan.png (100%) rename content/{media => articles/2008-05-04-using-the-canoscan-lide-500f-with-mac-os-x-leopard}/canondrivercontents.png (100%) create mode 100644 content/articles/2008-05-04-using-the-canoscan-lide-500f-with-mac-os-x-leopard/canoscanlide500f.jpg rename content/articles/{2008-05-04-using-the-canoscan-lide-500f-with-mac-os-x-leopard.md => 2008-05-04-using-the-canoscan-lide-500f-with-mac-os-x-leopard/index.md} (93%) rename content/{media => articles/2008-05-04-using-the-canoscan-lide-500f-with-mac-os-x-leopard}/scangear16bit.png (100%) rename content/{media => articles/2008-05-04-using-the-canoscan-lide-500f-with-mac-os-x-leopard}/scangear48bit.png (100%) rename content/{media => articles/2008-05-04-using-the-canoscan-lide-500f-with-mac-os-x-leopard}/scangear_color.png (100%) rename content/{media => articles/2008-05-04-using-the-canoscan-lide-500f-with-mac-os-x-leopard}/scangearwindow.png (100%) rename content/{media => articles/2008-05-04-using-the-canoscan-lide-500f-with-mac-os-x-leopard}/scanwindow_preview.png (100%) delete mode 100644 content/articles/2008-05-05-scan-images-directly-into-apple-aperture.md rename content/{media => articles/2008-05-05-scan-images-directly-into-apple-aperture}/apertureimport_automatic.png (100%) rename content/{media => articles/2008-05-05-scan-images-directly-into-apple-aperture}/apertureimport_automator.png (100%) rename content/{media => articles/2008-05-05-scan-images-directly-into-apple-aperture}/apertureimportplugin.png (100%) create mode 100644 content/articles/2008-05-05-scan-images-directly-into-apple-aperture/aperturescan.png rename content/{media => articles/2008-05-05-scan-images-directly-into-apple-aperture}/automator.png (100%) create mode 100644 content/articles/2008-05-05-scan-images-directly-into-apple-aperture/index.md rename content/articles/{2008-05-07-high-quality-watermarks-with-aperture.md => 2008-05-07-high-quality-watermarks-with-aperture/index.md} (84%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermark_1.png (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermark_2.png (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermark_3.png (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermark_4.png (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermark_5.png (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermark_6.png (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermark_7.png (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermark_8.png (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermark_9.png (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermark_aperture.jpg (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermark_example_by_kremalicious.zip (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermarkexample_final.jpg (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermarkexample_v2.jpg (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermarkexample_v3.jpg (100%) rename content/{media => articles/2008-05-07-high-quality-watermarks-with-aperture}/watermarkexample_v4.jpg (100%) rename content/articles/{2008-05-07-nik-ships-viveza-as-the-first-available-aperture-editing-plugin.md => 2008-05-07-nik-ships-viveza-as-the-first-available-aperture-editing-plugin/index.md} (78%) rename content/{media => articles/2008-05-07-nik-ships-viveza-as-the-first-available-aperture-editing-plugin}/viveza.png (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_1.png (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_10.png (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_11.png (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_12.png (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_13.png (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_14.jpg (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_15.png (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_2.png (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_3.png (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_4.png (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_5.png (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_6.png (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_7.png (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_8.jpg (100%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/aperture15_8.png (100%) rename content/articles/{2008-05-07-the-15-best-new-features-of-aperture-2.md => 2008-05-07-the-15-best-new-features-of-aperture-2/index.md} (85%) rename content/{media => articles/2008-05-07-the-15-best-new-features-of-aperture-2}/raw20.png (100%) rename content/articles/{2008-05-08-the-iconfactory-presents-beautiful-indiana-jones-desktop-icons.md => 2008-05-08-the-iconfactory-presents-beautiful-indiana-jones-desktop-icons/index.md} (57%) rename content/{media => articles/2008-05-08-the-iconfactory-presents-beautiful-indiana-jones-desktop-icons}/indianajones_dock.png (100%) rename content/{media => articles/2008-05-08-the-iconfactory-presents-beautiful-indiana-jones-desktop-icons}/indianajones_first.png (100%) rename content/articles/{2008-05-14-canon-updates-its-photographic-software-to-work-with-leopard.md => 2008-05-14-canon-updates-its-photographic-software-to-work-with-leopard/index.md} (100%) create mode 100644 content/articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived/aperture97.png rename content/{media => articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived}/apertureedit_interface.jpg (100%) rename content/{media => articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived}/creaceed_hydra.png (100%) rename content/{media => articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived}/dft-light_ui.jpg (100%) rename content/{media => articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived}/dft-ozone_ui.jpg (100%) rename content/{media => articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived}/dft-powerstroke_uis.jpg (100%) rename content/{media => articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived}/dpmatte_index1.jpg (100%) rename content/{media => articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived}/imagestrends_shieoff.jpg (100%) rename content/{media => articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived}/imagetrends_hemi_10.jpg (100%) rename content/{media => articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived}/imagetrends_pearlywhite.png (100%) rename content/articles/{2008-05-18-first-aperture-adjustment-plugins-have-arrived.md => 2008-05-18-first-aperture-adjustment-plugins-have-arrived/index.md} (80%) rename content/{media => articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived}/lensfix_ci.png (100%) rename content/{media => articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived}/noiseninja.png (100%) rename content/{media => articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived}/tiffen_aperture.jpg (100%) rename content/{media => articles/2008-05-18-first-aperture-adjustment-plugins-have-arrived}/viveza_aperture_ui.jpg (100%) create mode 100644 content/articles/2008-05-19-image-trends-releases-fisheye-hemi-plug-in-for-aperture/imagetrends_hemi_10.jpg rename content/articles/{2008-05-19-image-trends-releases-fisheye-hemi-plug-in-for-aperture.md => 2008-05-19-image-trends-releases-fisheye-hemi-plug-in-for-aperture/index.md} (74%) rename content/articles/{2008-05-21-awesome-parallax-optical-illusion.md => 2008-05-21-awesome-parallax-optical-illusion/index.md} (57%) rename content/{media => articles/2008-05-21-awesome-parallax-optical-illusion}/parallax_illusion_css.png (100%) rename content/articles/{2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages.md => 2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages/index.md} (82%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax-visualization.png (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax-visualization_big.png (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_001.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_002.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_003.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_004.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_005.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_006.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_007.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_008.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_009.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_010.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_011.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_012.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_013.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_014.png (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_015.png (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_016.jpg (100%) rename content/{media => articles/2008-05-22-showcasing-the-css-parallax-effect-12-creative-usages}/parallax_017.jpg (100%) rename content/{media => articles/2008-05-28-new-all-in-one-aperture-plug-in-released}/apertureedit_logo.png (100%) rename content/articles/{2008-05-28-new-all-in-one-aperture-plug-in-released.md => 2008-05-28-new-all-in-one-aperture-plug-in-released/index.md} (69%) delete mode 100644 content/articles/2008-06-01-chives.md rename content/{media => articles/2008-06-01-chives}/Teaser-Chives.jpg (100%) rename content/{media => articles/2008-06-01-chives}/chives_by_kremalicious.zip (100%) create mode 100644 content/articles/2008-06-01-chives/index.md rename content/articles/{2008-06-02-tweet-im-on-twitter-now.md => 2008-06-02-tweet-im-on-twitter-now/index.md} (71%) rename content/{media => articles/2008-06-02-tweet-im-on-twitter-now}/twitter-bird-kremalicious.png (100%) rename content/{media => articles/2008-06-02-tweet-im-on-twitter-now}/twitter.png (100%) rename content/{media => articles/2008-06-03-niepces-camera-obscura-and-the-history-of-the-first-photograph}/Teaser-Camera-Obscura-Icons.jpg (100%) rename content/{media => articles/2008-06-03-niepces-camera-obscura-and-the-history-of-the-first-photograph}/View-from-the-Window-at-Le-Gras.png (100%) rename content/{media => articles/2008-06-03-niepces-camera-obscura-and-the-history-of-the-first-photograph}/cameraobscura11_all.png (100%) rename content/{media => articles/2008-06-03-niepces-camera-obscura-and-the-history-of-the-first-photograph}/cameraobscura_inuse.png (100%) rename content/{media => articles/2008-06-03-niepces-camera-obscura-and-the-history-of-the-first-photograph}/coffee-cup-empty.png (100%) rename content/articles/{2008-06-03-niepces-camera-obscura-and-the-history-of-the-first-photograph.md => 2008-06-03-niepces-camera-obscura-and-the-history-of-the-first-photograph/index.md} (90%) rename content/{media => articles/2008-06-03-niepces-camera-obscura-and-the-history-of-the-first-photograph}/nicephore-niepce.jpg (100%) rename content/{media => articles/2008-06-03-niepces-camera-obscura-and-the-history-of-the-first-photograph}/niepces_camera_obscura_by_kremalicious.zip (100%) rename content/{media => articles/2008-06-03-niepces-camera-obscura-and-the-history-of-the-first-photograph}/view_from_the_window_at_le_gras_nicephore_niepce.jpg (100%) rename content/{media => articles/2008-06-03-niepces-camera-obscura-wallpaper-pack}/Teaser-Camera-Obscura-Walls.jpg (100%) rename content/articles/{2008-06-03-niepces-camera-obscura-wallpaper-pack.md => 2008-06-03-niepces-camera-obscura-wallpaper-pack/index.md} (77%) rename content/{media => articles/2008-06-03-niepces-camera-obscura-wallpaper-pack}/niepces_camera_obscura_wallpaper_pack_by_kremalicious.zip (100%) rename content/articles/{2008-06-11-safari-4-developer-preview.md => 2008-06-11-safari-4-developer-preview/index.md} (87%) rename content/{media => articles/2008-06-11-safari-4-developer-preview}/safari-logo.png (100%) rename content/{media => articles/2008-06-11-safari-4-developer-preview}/safari4_zoom.png (100%) rename content/{media => articles/2008-06-11-safari-4-developer-preview}/safari_4_tabs.png (100%) rename content/{media => articles/2008-06-11-safari-4-developer-preview}/webinspector_2.png (100%) rename content/{media => articles/2008-06-11-safari-4-developer-preview}/webinspector_3.png (100%) rename content/{media => articles/2008-06-17-quick-tip-borders-titles-plug-in-for-aperture}/aperture128.png (100%) rename content/{media => articles/2008-06-17-quick-tip-borders-titles-plug-in-for-aperture}/aperture_bt.png (100%) rename content/articles/{2008-06-17-quick-tip-borders-titles-plug-in-for-aperture.md => 2008-06-17-quick-tip-borders-titles-plug-in-for-aperture/index.md} (74%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/bonjour97.png (100%) create mode 100644 content/articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume/coffee-cup-empty.png rename content/articles/{2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume.md => 2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume/index.md} (87%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/netatalk.png (100%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/server_displays_by_kremalicious.zip (100%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/serverdisplays.jpg (100%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/timemachine97.png (100%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/timemachinedisk97.png (100%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/tm-sparsebundle.png (100%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/ubuntu_mac_feature.jpg (100%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/ubuntuserver1.png (100%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/ubuntuserver2.png (100%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/ubuntuserver3.png (100%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/ubuntuserver4.png (100%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/ubuntuserver4a.png (100%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/ubuntuserver5.png (100%) rename content/{media => articles/2008-06-19-ubuntu-as-mac-file-server-and-time-machine-volume}/ubuntuserver97.png (100%) rename content/{media => articles/2008-06-25-apertureedit-is-edit-for-aperture-now-updated-to-12}/apertureedit_logo2.png (100%) rename content/articles/{2008-06-25-apertureedit-is-edit-for-aperture-now-updated-to-12.md => 2008-06-25-apertureedit-is-edit-for-aperture-now-updated-to-12/index.md} (69%) delete mode 100644 content/articles/2008-06-25-new-canon-stuff-xs-eos-1000-430ex-ii.md rename content/{media => articles/2008-06-25-new-canon-stuff-xs-eos-1000-430ex-ii}/canon1000d.png (100%) create mode 100644 content/articles/2008-06-25-new-canon-stuff-xs-eos-1000-430ex-ii/index.md rename content/{media => articles/2008-06-25-new-canon-stuff-xs-eos-1000-430ex-ii}/speedlite430exii.jpg (100%) delete mode 100644 content/articles/2008-07-01-everything-back-to-normal-on-kremaliciouscom-almost.md rename content/{media => articles/2008-07-08-new-aperture-plug-ins-jade-and-ptlens}/aperture-plugin128.png (100%) rename content/articles/{2008-07-08-new-aperture-plug-ins-jade-and-ptlens.md => 2008-07-08-new-aperture-plug-ins-jade-and-ptlens/index.md} (93%) rename content/{media => articles/2008-07-08-new-aperture-plug-ins-jade-and-ptlens}/jade_ui.png (100%) rename content/{media => articles/2008-07-08-new-aperture-plug-ins-jade-and-ptlens}/ptlens_ui.png (100%) rename content/articles/{2008-07-11-enjoy-kremaliciousiphone.md => 2008-07-11-enjoy-kremaliciousiphone/index.md} (85%) rename content/{media => articles/2008-07-11-enjoy-kremaliciousiphone}/kremalicious-iconiphone.png (100%) rename content/{media => articles/2008-07-11-enjoy-kremaliciousiphone}/kremaliciousiphone.png (100%) delete mode 100644 content/articles/2008-07-11-new-aperture-plug-in-nik-announces-silver-efex-pro.md create mode 100644 content/articles/2008-07-11-new-aperture-plug-in-nik-announces-silver-efex-pro/aperture-plugin128.png create mode 100644 content/articles/2008-07-11-new-aperture-plug-in-nik-announces-silver-efex-pro/index.md rename content/{media => articles/2008-07-11-new-aperture-plug-in-nik-announces-silver-efex-pro}/nik_silverefex.png (100%) rename content/articles/{2008-07-15-wordpress-25-get-rid-of-that-sluggish-dashboard.md => 2008-07-15-wordpress-25-get-rid-of-that-sluggish-dashboard/index.md} (72%) rename content/{media => articles/2008-07-15-wordpress-25-get-rid-of-that-sluggish-dashboard}/wordpress-logo.png (100%) rename content/articles/{2008-08-03-tips-for-journalists-reporting-from-china.md => 2008-08-03-tips-for-journalists-reporting-from-china/index.md} (98%) rename content/{media => articles/2008-08-03-tips-for-journalists-reporting-from-china}/jingjing_chacha_kremalicious.jpg (100%) rename content/articles/{2008-08-22-howto-create-a-mobile-encrypted-aperture-vault.md => 2008-08-22-howto-create-a-mobile-encrypted-aperture-vault/index.md} (75%) rename content/{media => articles/2008-08-22-howto-create-a-mobile-encrypted-aperture-vault}/niepces_aperture_vault256.png (100%) rename content/{media => articles/2008-08-22-howto-create-a-mobile-encrypted-aperture-vault}/securevault1.png (100%) rename content/{media => articles/2008-08-22-howto-create-a-mobile-encrypted-aperture-vault}/securevault2.png (100%) rename content/{media => articles/2008-08-22-howto-create-a-mobile-encrypted-aperture-vault}/securevault3.png (100%) rename content/{media => articles/2008-08-22-howto-create-a-mobile-encrypted-aperture-vault}/securevault4.png (100%) rename content/{media => articles/2008-08-22-howto-create-a-mobile-encrypted-aperture-vault}/securevault5.png (100%) create mode 100644 content/articles/2008-08-22-noise-ninja-finally-available-for-apple-aperture/aperture-plugin128.png rename content/articles/{2008-08-22-noise-ninja-finally-available-for-apple-aperture.md => 2008-08-22-noise-ninja-finally-available-for-apple-aperture/index.md} (60%) rename content/articles/{2008-08-22-the-kremalicious-marsedit-style.md => 2008-08-22-the-kremalicious-marsedit-style/index.md} (75%) rename content/{media => articles/2008-08-22-the-kremalicious-marsedit-style}/marsedit_kremalicious.png (100%) rename content/{media => articles/2008-08-22-the-kremalicious-marsedit-style}/marsedit_kremalicious.txt (100%) rename content/{media => articles/2008-08-22-the-kremalicious-marsedit-style}/marsedit_kremalicious_big.png (100%) rename content/{media => articles/2008-08-26-icy-box-icons}/Teaser-Icy-Box.jpg (100%) rename content/{media/icybox_teaser2.jpg => articles/2008-08-26-icy-box-icons/icybox.jpg} (100%) rename content/{media => articles/2008-08-26-icy-box-icons}/icybox_by_kremalicious.zip (100%) rename content/articles/{2008-08-26-icy-box-icons.md => 2008-08-26-icy-box-icons/index.md} (78%) rename content/{media => articles/2008-08-28-architect-and-facade-theming-for-leopard}/architect-icon.jpg (100%) rename content/{media => articles/2008-08-28-architect-and-facade-theming-for-leopard}/architect-ui.png (100%) rename content/articles/{2008-08-28-architect-and-facade-theming-for-leopard.md => 2008-08-28-architect-and-facade-theming-for-leopard/index.md} (76%) rename content/{media => articles/2008-08-28-architect-and-facade-theming-for-leopard}/magnifique-ui.png (100%) delete mode 100644 content/articles/2008-08-28-canon-eos-50d-new-lens-announced.md rename content/{media => articles/2008-08-28-canon-eos-50d-new-lens-announced}/efs_18-200.png (100%) rename content/{media => articles/2008-08-28-canon-eos-50d-new-lens-announced}/eos_50D_back.png (100%) rename content/{media => articles/2008-08-28-canon-eos-50d-new-lens-announced}/eos_50D_front.png (100%) create mode 100644 content/articles/2008-08-28-canon-eos-50d-new-lens-announced/index.md rename content/{media => articles/2008-09-01-a-new-browser-is-coming-google-chrome}/chrome-ui.png (100%) rename content/{media => articles/2008-09-01-a-new-browser-is-coming-google-chrome}/googlechrome.png (100%) rename content/articles/{2008-09-01-a-new-browser-is-coming-google-chrome.md => 2008-09-01-a-new-browser-is-coming-google-chrome/index.md} (60%) rename content/{media => articles/2008-09-23-futurama-mars-university-wallpaper}/Teaser-Mars-U.jpg (100%) rename content/articles/{2008-09-23-futurama-mars-university-wallpaper.md => 2008-09-23-futurama-mars-university-wallpaper/index.md} (66%) rename content/{media => articles/2008-09-23-futurama-mars-university-wallpaper}/mars-u-wall-by-kremalicious.zip (100%) rename content/{media => articles/2008-10-23-coffee-cup-icon}/Teaser-Coffee-Cup-Icon.jpg (100%) rename content/{media => articles/2008-10-23-coffee-cup-icon}/coffee_cup_by_kremalicious.zip (100%) rename content/articles/{2008-10-23-coffee-cup-icon.md => 2008-10-23-coffee-cup-icon/index.md} (75%) create mode 100644 content/articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web/Teaser-Coffee-Cup-Icon.jpg rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-apple.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-baumann.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-benedik.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-brasgalla.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-brasgalla2.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-cappuccinosofa.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-england.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-flarup.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-jaeppinen.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-kaycaffeine.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-kretschmann.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-lanham.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-lopezruiz.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-lovecappu.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-macrabbit.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-matu.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-rask1.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-rask2.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-susumo.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-times.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-tut-abduzeedo.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-tut-houle.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-tut-psdtuts.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-tut-vectuts.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-vegrafik.png (100%) rename content/{media => articles/2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web}/coffee-showcase-visualpharm.png (100%) rename content/articles/{2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web.md => 2008-10-23-the-finest-coffee-cups-most-incredible-coffee-icons-on-the-web/index.md} (67%) rename content/{media => articles/2008-10-26-the-definite-guide-to-watermarks-in-apple-aperture}/aperture-impression.png (100%) rename content/{media => articles/2008-10-26-the-definite-guide-to-watermarks-in-apple-aperture}/aperture_borderfx.png (100%) create mode 100644 content/articles/2008-10-26-the-definite-guide-to-watermarks-in-apple-aperture/aperture_bt.png rename content/articles/{2008-10-26-the-definite-guide-to-watermarks-in-apple-aperture.md => 2008-10-26-the-definite-guide-to-watermarks-in-apple-aperture/index.md} (89%) create mode 100644 content/articles/2008-10-26-the-definite-guide-to-watermarks-in-apple-aperture/watermark_5.png create mode 100644 content/articles/2008-10-26-the-definite-guide-to-watermarks-in-apple-aperture/watermark_8.png create mode 100644 content/articles/2008-10-26-the-definite-guide-to-watermarks-in-apple-aperture/watermark_aperture.jpg rename content/{media => articles/2008-12-11-how-to-set-a-custom-gravatar-image-in-wordpress-27}/custom-gravatar.jpg (100%) rename content/articles/{2008-12-11-how-to-set-a-custom-gravatar-image-in-wordpress-27.md => 2008-12-11-how-to-set-a-custom-gravatar-image-in-wordpress-27/index.md} (80%) rename content/articles/{2008-12-13-howto-styling-author-comments-with-wordpress-27.md => 2008-12-13-howto-styling-author-comments-with-wordpress-27/index.md} (75%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-01.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-02.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-03.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-04.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-05.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-06.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-07.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-08.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-09.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-10.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-11.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-12.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-13.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-14.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-15.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-16.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-17.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-18.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-19.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-20.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-21.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama-mac-teaser.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama_gedeon.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama_hawkins1.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama_hawkins2.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama_kremalicious.png (100%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/futurama_rawpixels.png (100%) rename content/articles/{2009-01-05-the-mac-in-futurama.md => 2009-01-05-the-mac-in-futurama/index.md} (64%) rename content/{media => articles/2009-01-05-the-mac-in-futurama}/out_of_whale_oil_detail.png (100%) rename content/articles/{2009-02-01-portal-thingy.md => 2009-02-01-portal-thingy/index.md} (88%) rename content/{media => articles/2009-02-01-portal-thingy}/vcardsite-arefjdey.png (100%) rename content/{media => articles/2009-02-01-portal-thingy}/vcardsite-laurent.png (100%) rename content/{media => articles/2009-02-01-portal-thingy}/vcardsite-maximilian.png (100%) rename content/{media => articles/2009-02-01-portal-thingy}/vcardsite-mk.png (100%) rename content/{media => articles/2009-02-01-portal-thingy}/vcardsite-rogie.png (100%) rename content/{media => articles/2009-02-01-portal-thingy}/vcardsite-tim.png (100%) rename content/{media => articles/2009-02-17-out-of-whale-oil}/Teaser-Out-Of-Whale-Oil.jpg (100%) rename content/articles/{2009-02-17-out-of-whale-oil.md => 2009-02-17-out-of-whale-oil/index.md} (67%) rename content/{media => articles/2009-02-17-out-of-whale-oil}/out-of-whale-oil-overview.png (100%) rename content/{media => articles/2009-02-17-out-of-whale-oil}/out-of-whale-oil-wall-by-kremalicious.zip (100%) create mode 100644 content/articles/2009-02-17-out-of-whale-oil/out_of_whale_oil_detail.png rename content/{media => articles/2009-03-29-ultimate-coda-wordpress-share-link-bonanza}/coda-clips-icon-files.zip (100%) rename content/{media => articles/2009-03-29-ultimate-coda-wordpress-share-link-bonanza}/codaclips-hud.png (100%) rename content/{media => articles/2009-03-29-ultimate-coda-wordpress-share-link-bonanza}/codaclips-icon128.png (100%) rename content/{media => articles/2009-03-29-ultimate-coda-wordpress-share-link-bonanza}/codaclips-placeholder.png (100%) rename content/{media => articles/2009-03-29-ultimate-coda-wordpress-share-link-bonanza}/codaclips-teaser.png (100%) rename content/{media => articles/2009-03-29-ultimate-coda-wordpress-share-link-bonanza}/coffee-cup-icon-kremalicious.png (100%) rename content/articles/{2009-03-29-ultimate-coda-wordpress-share-link-bonanza.md => 2009-03-29-ultimate-coda-wordpress-share-link-bonanza/index.md} (64%) rename content/{media => articles/2009-03-29-ultimate-coda-wordpress-share-link-bonanza}/share-link-bonanza-coda-clips.zip (100%) rename content/{media => articles/2009-03-29-ultimate-coda-wordpress-share-link-bonanza}/share-link-bonanza-html.zip (100%) rename content/{media => articles/2009-03-29-ultimate-coda-wordpress-share-link-bonanza}/tutorial-icon.png (100%) rename content/{media => articles/2009-06-04-twitter-crisp}/Teaser-Twitter-Crisp.jpg (100%) rename content/articles/{2009-06-04-twitter-crisp.md => 2009-06-04-twitter-crisp/index.md} (73%) rename content/{media => articles/2009-06-04-twitter-crisp}/twitter-crisp-by-kremalicious.zip (100%) rename content/{media => articles/2009-06-24-adiumeetie}/Adiumeetie-Dock-Preview.png (100%) rename content/{media => articles/2009-06-24-adiumeetie}/Adiumeetie-Teaser-AdiumIcon.png (100%) rename content/{media => articles/2009-06-24-adiumeetie}/Adiumeetie-Teaser.jpg (100%) rename content/{media => articles/2009-06-24-adiumeetie}/Teaser-Adiumeetie.jpg (100%) rename content/{media => articles/2009-06-24-adiumeetie}/adiumeetie-by-kremalicious.zip (100%) rename content/articles/{2009-06-24-adiumeetie.md => 2009-06-24-adiumeetie/index.md} (75%) rename content/{media => articles/2009-09-05-delibar}/Teaser-Delibar-Icons.jpg (100%) rename content/{media => articles/2009-09-05-delibar}/delibar-by-kremalicious.zip (100%) rename content/articles/{2009-09-05-delibar.md => 2009-09-05-delibar/index.md} (78%) rename content/articles/{2009-12-17-wordpress-post-thumbnails.md => 2009-12-17-wordpress-post-thumbnails/index.md} (68%) rename content/{media => articles/2009-12-17-wordpress-post-thumbnails}/wordpress-thumbnail-1.png (100%) rename content/{media => articles/2009-12-17-wordpress-post-thumbnails}/wordpress-thumbnail-2.png (100%) rename content/{media => articles/2009-12-17-wordpress-post-thumbnails}/wordpress-thumbnail-3.png (100%) rename content/{media => articles/2009-12-17-wordpress-post-thumbnails}/wordpress-thumbnail-4.png (100%) rename content/{media => articles/2009-12-17-wordpress-post-thumbnails}/wordpress-thumbnail-5.png (100%) rename content/{media => articles/2010-02-04-ipixelpad}/Teaser-iPixelPad.png (100%) rename content/{media => articles/2010-02-04-ipixelpad}/iPixelPad-Teaser-kremalicious2.jpg (100%) rename content/{media => articles/2010-02-04-ipixelpad}/iPixelPad-Teaser1.png (100%) rename content/articles/{2010-02-04-ipixelpad.md => 2010-02-04-ipixelpad/index.md} (76%) rename content/{media => articles/2010-02-04-ipixelpad}/ipixelpad-homescreen-zoom.png (100%) rename content/{media => articles/2010-02-04-ipixelpad}/ipixelpad_by_kremalicious.zip (100%) rename content/{media => articles/2010-07-03-momcorp}/MomCorp-Walls-Overview.png (100%) rename content/{media => articles/2010-07-03-momcorp}/Teaser-MomCorp-Wall.png (100%) rename content/articles/{2010-07-03-momcorp.md => 2010-07-03-momcorp/index.md} (74%) rename content/{media => articles/2010-07-03-momcorp}/momcorp_wall_by_kremalicious.zip (100%) rename content/{media/Badged-Teaser-kremalicious@2x.png => articles/2011-12-15-badged/Badged-Teaser-kremalicious.png} (100%) rename content/{media => articles/2011-12-15-badged}/badged-settings.png (100%) rename content/articles/{2011-12-15-badged.md => 2011-12-15-badged/index.md} (97%) rename content/articles/{2012-02-26-mk-v2.md => 2012-02-26-mk-v2/index.md} (89%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2-android-chrome.png (100%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2-android-firefox.png (100%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2-android.png (100%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2-balls.jpg (100%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2-detail.png (100%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2-ipad-touchindicator.jpg (100%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2-ipad.png (100%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2-iphone.png (100%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2-portfolio-overlay.jpg (100%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2-responsivelayouts.jpg (100%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2-teaser-450x250.jpg (100%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2-teaser-500x277.jpg (100%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2-teaser-540x288.jpg (100%) rename content/{media => articles/2012-02-26-mk-v2}/mkv2.jpg (100%) rename content/{media => articles/2012-04-04-android-tab-conundrum}/Instagram-Swipe.png (100%) rename content/{media => articles/2012-04-04-android-tab-conundrum}/android-galaxy-note.png (100%) rename content/{media => articles/2012-04-04-android-tab-conundrum}/android-navigation-buttons.png (100%) rename content/articles/{2012-04-04-android-tab-conundrum.md => 2012-04-04-android-tab-conundrum/index.md} (95%) rename content/{media => articles/2012-04-04-android-tab-conundrum}/tabs_overview.png (100%) rename content/articles/{2012-05-14-welcome-to-kremalicious2.md => 2012-05-14-welcome-to-kremalicious2/index.md} (92%) rename content/{media => articles/2012-05-14-welcome-to-kremalicious2}/kremalicious2-photogrid.jpg (100%) rename content/{media => articles/2012-05-14-welcome-to-kremalicious2}/kremalicious2-photoposts.jpg (100%) rename content/{media => articles/2012-05-14-welcome-to-kremalicious2}/kremalicious2-teaser.jpg (100%) rename content/{media => articles/2012-05-14-welcome-to-kremalicious2}/kremalicious2-topicicons.jpg (100%) rename content/{media => articles/2012-05-14-welcome-to-kremalicious2}/kremalicious2-typography.jpg (100%) rename content/{media => articles/2012-05-14-welcome-to-kremalicious2}/kremaliciouscom-iPad-3.jpg (100%) rename content/{media => articles/2012-05-15-wp-icons-template}/WordPress-Admin-Icons-Template-Filled.png (100%) rename content/articles/{2012-05-15-wp-icons-template.md => 2012-05-15-wp-icons-template/index.md} (98%) rename content/{media => articles/2012-05-15-wp-icons-template}/kremalicious-Teaser-WP-Icon-Template.png (100%) rename content/articles/{2012-06-13-retina-icons-in-wordpress-3-4.md => 2012-06-13-retina-icons-in-wordpress-3-4/index.md} (90%) create mode 100644 content/articles/2012-06-13-retina-icons-in-wordpress-3-4/kremalicious-Teaser-WP-Icon-Template.png rename content/{media => articles/2012-06-13-retina-icons-in-wordpress-3-4}/wp34_retina_icons.png (100%) rename content/{media => articles/2012-07-15-add-your-web-site-to-the-windows-8-metro-ui}/Windows-8-Metro-tile-kremalicious-all-apps.png (100%) rename content/{media => articles/2012-07-15-add-your-web-site-to-the-windows-8-metro-ui}/Windows-8-Metro-tile-kremalicious-in-action.png (100%) rename content/{media => articles/2012-07-15-add-your-web-site-to-the-windows-8-metro-ui}/Windows-8-Metro-tile-kremalicious.png (100%) rename content/articles/{2012-07-15-add-your-web-site-to-the-windows-8-metro-ui.md => 2012-07-15-add-your-web-site-to-the-windows-8-metro-ui/index.md} (89%) rename content/{media => articles/2012-07-15-add-your-web-site-to-the-windows-8-metro-ui}/kremalicious-Teaser-Metro-Tile.jpg (100%) delete mode 100644 content/articles/2012-07-16-using-kbd-for-fun-and-profit/Google Android License.txt delete mode 100644 content/articles/2012-07-16-using-kbd-for-fun-and-profit/Roboto-Regular-webfont.eot delete mode 100644 content/articles/2012-07-16-using-kbd-for-fun-and-profit/Roboto-Regular-webfont.svg delete mode 100644 content/articles/2012-07-16-using-kbd-for-fun-and-profit/Roboto-Regular-webfont.ttf delete mode 100644 content/articles/2012-07-16-using-kbd-for-fun-and-profit/Roboto-Regular-webfont.woff create mode 100644 content/articles/2012-07-16-using-kbd-for-fun-and-profit/_post-kbd.css delete mode 100644 content/articles/2012-07-16-using-kbd-for-fun-and-profit/post-kbd.css rename content/{media => articles/2012-08-07-projectpurple}/Project-Purple-Dribbble.png (100%) rename content/{media => articles/2012-08-07-projectpurple}/Teaser-Project-Purple.png (100%) rename content/articles/{2012-08-07-projectpurple.md => 2012-08-07-projectpurple/index.md} (58%) rename content/{media => articles/2012-08-07-projectpurple}/project-purple-ipad-kremalicious.png (100%) rename content/{media => articles/2012-08-07-projectpurple}/project-purple-iphone4-kremalicious.png (100%) rename content/{media => articles/2012-08-07-projectpurple}/project-purple-kremalicious.png (100%) rename content/{media => articles/2012-08-07-projectpurple}/project-purple-kremalicious.zip (100%) rename content/{media => articles/2012-08-07-projectpurple}/project-purple-nexus-kremalicious.png (100%) rename content/articles/{2012-08-20-im-joining-ezeep.md => 2012-08-20-im-joining-ezeep/index.md} (94%) rename content/{media => articles/2012-08-20-im-joining-ezeep}/kremalicious-Teaser-ezeep.png (100%) rename content/{media => articles/2013-07-13-enterprise-software-sucks}/buddha-colorscheme.png (100%) rename content/{media => articles/2013-07-13-enterprise-software-sucks}/buddha-printer.png (100%) rename content/articles/{2013-07-13-enterprise-software-sucks.md => 2013-07-13-enterprise-software-sucks/index.md} (97%) rename content/articles/{2013-08-07-stealing-time-how-technology-can-hurt-or-harm-our-inner-state.md => 2013-08-07-stealing-time-how-technology-can-hurt-or-harm-our-inner-state/index.md} (99%) rename content/{media => articles/2013-08-07-stealing-time-how-technology-can-hurt-or-harm-our-inner-state}/post-time.png (100%) rename content/articles/{2015-09-13-css-app-store-badges.md => 2015-09-13-css-app-store-badges/index.md} (92%) rename content/{media => articles/2015-09-13-css-app-store-badges}/teaser-appstorebadges.png (100%) create mode 100644 content/articles/2023-09-18-favicon-generation-with-astro/favicon-generation-with-astro-teaser.png create mode 100644 content/articles/2023-09-18-favicon-generation-with-astro/index.md create mode 100644 content/config.ts delete mode 100644 content/media/Badged-Teaser-kremalicious.png delete mode 100644 content/media/Delibar-Icons-Teaser.jpg delete mode 100644 content/media/Delibar-Icons-Teaser2.png delete mode 100644 content/media/Twitter-Crisp-16.png delete mode 100644 content/media/adiumeetie-goodies-teaser.png delete mode 100644 content/media/aperture72.png delete mode 100644 content/media/box_download.png delete mode 100644 content/media/camera_obscura_wall_teaser.png delete mode 100644 content/media/cameraobscura11_all_thumb.png delete mode 100644 content/media/cameraobscura_aperture_128.png delete mode 100644 content/media/cameraobscura_teaser1.png delete mode 100644 content/media/ce2d29f40df411e2ad5812313817873b_7.jpg delete mode 100644 content/media/chives_wallpaper_teaser.png delete mode 100644 content/media/codaclips-icon48.png delete mode 100644 content/media/coffee-cup-icon-teaser.png delete mode 100644 content/media/delibar-website.png delete mode 100644 content/media/deliciouslinks.png delete mode 100644 content/media/diskimage98.png delete mode 100644 content/media/efs_18-200_thumb.png delete mode 100644 content/media/elegancesociale_smashingteaser.png delete mode 100644 content/media/encryption_certificate.png delete mode 100644 content/media/encryption_mail2.png delete mode 100644 content/media/eos_50D_back_thumb.png delete mode 100644 content/media/eos_50D_front_thumb.png delete mode 100644 content/media/filevault98.png delete mode 100644 content/media/firefox-icon.png delete mode 100644 content/media/firefox3promo.png delete mode 100644 content/media/free-pdf.png delete mode 100644 content/media/fry-2009-kremalicious.png delete mode 100644 content/media/hastuzeit-kremalicious2.jpg delete mode 100644 content/media/html-document-icon48.png delete mode 100644 content/media/icon-Facebook.png delete mode 100644 content/media/icon-Twitter2.png delete mode 100644 content/media/icon-deviantART.png delete mode 100644 content/media/icybox_teaser1.png delete mode 100644 content/media/icybox_teaser2_small.png delete mode 100644 content/media/jade_ui_thumb.jpg delete mode 100644 content/media/kremalicious-iconiphone-80.png delete mode 100644 content/media/kremalicious_nav.txt delete mode 100644 content/media/kremaliciousiphone_thumb.png delete mode 100644 content/media/lens.png delete mode 100644 content/media/mars-u-teaser.png delete mode 100644 content/media/mediaMomCorpTeaser.png delete mode 100644 content/media/niepce_portrait.png delete mode 100644 content/media/nik_silverefex_thumb.png delete mode 100644 content/media/opera-icon.png delete mode 100644 content/media/paypal-logo.jpg delete mode 100644 content/media/ptlens_ui_thumb.jpg delete mode 100644 content/media/republica-banner-125x160_black.png delete mode 100644 content/media/republica10_kremaliciousbanner.png delete mode 100644 content/media/safari4_zoom_thumb.png delete mode 100644 content/media/snippet.png delete mode 100644 content/media/softwareupdate.png delete mode 100644 content/media/softwareupdate_photo200.png delete mode 100644 content/media/teaser-out-of-whale-oil.png delete mode 100644 content/media/teaser_elegance-sociale.png delete mode 100644 content/media/tweetie_select_bubbles.zip delete mode 100644 content/media/twitter-crisp-teaser.jpg delete mode 100644 content/media/twitter-crisp-teaser2.png delete mode 100644 content/media/webinspector_1.png delete mode 100644 content/media/xserve_screwed.png rename content/{media => photos/2005-07-26-beaucarnea-leafs}/img_1820-Version-4.jpg (100%) rename content/photos/{2005-07-26-beaucarnea-leafs.md => 2005-07-26-beaucarnea-leafs/index.md} (84%) rename content/photos/{2005-08-02-snail-on-a-leaf.md => 2005-08-02-snail-on-a-leaf/index.md} (86%) rename content/{media => photos/2005-08-02-snail-on-a-leaf}/schnecke_blatt.jpg (100%) rename content/{media => photos/2006-07-23-electricity}/MG_5885_2006-7-23.jpg (100%) rename content/photos/{2006-07-23-electricity.md => 2006-07-23-electricity/index.md} (84%) rename content/{media => photos/2006-07-23-floating-sky}/floating-sky-1.jpg (100%) rename content/photos/{2006-07-23-floating-sky.md => 2006-07-23-floating-sky/index.md} (90%) rename content/{media => photos/2006-08-21-new-berlin-bridge}/berliner_bruecke1-HDR-16bit.jpg (100%) rename content/photos/{2006-08-21-new-berlin-bridge.md => 2006-08-21-new-berlin-bridge/index.md} (79%) rename content/photos/{2006-09-16-wooden-windmill.md => 2006-09-16-wooden-windmill/index.md} (77%) rename content/{media => photos/2006-09-16-wooden-windmill}/muehle_suhlendorf_HDR_Tonemapped_16bit.jpg (100%) rename content/{media => photos/2006-10-22-german-chancellery}/bundeskanzleramt_01_HDR_tonemapped_16bit-Version-2.jpg (100%) rename content/photos/{2006-10-22-german-chancellery.md => 2006-10-22-german-chancellery/index.md} (74%) rename content/{media => photos/2007-02-10-macbook-abstract}/MG_9313_2007-02-10.jpg (100%) rename content/photos/{2007-02-10-macbook-abstract.md => 2007-02-10-macbook-abstract/index.md} (82%) rename content/{media => photos/2008-06-04-helvetica-typewriter-keys}/MG_1735-Version-2.jpg (100%) rename content/photos/{2008-06-04-helvetica-typewriter-keys.md => 2008-06-04-helvetica-typewriter-keys/index.md} (86%) rename content/photos/{2008-06-30-stone-head.md => 2008-06-30-stone-head/index.md} (89%) rename content/{media => photos/2008-06-30-stone-head}/stonehead.jpg (100%) rename content/{media => photos/2008-07-23-leaf-life}/MG_1920.jpg (100%) rename content/photos/{2008-07-23-leaf-life.md => 2008-07-23-leaf-life/index.md} (87%) rename content/{media => photos/2008-09-23-a-long-time-ago}/A-Long-Time-Ago.jpg (100%) rename content/photos/{2008-09-23-a-long-time-ago.md => 2008-09-23-a-long-time-ago/index.md} (93%) rename content/{media => photos/2010-03-27-office-desk}/Office-Desk.jpg (100%) rename content/photos/{2010-03-27-office-desk.md => 2010-03-27-office-desk/index.md} (86%) rename content/{media => photos/2010-07-18-typeface-condoms}/Typeface-condoms.jpg (100%) rename content/photos/{2010-07-18-typeface-condoms.md => 2010-07-18-typeface-condoms/index.md} (88%) rename content/{media => photos/2010-08-07-bonsai}/Bonsai-5-Version-2.jpg (100%) rename content/photos/{2010-08-07-bonsai.md => 2010-08-07-bonsai/index.md} (81%) rename content/{media => photos/2010-09-01-gdr-helvetica}/GDR-Helvetica.jpg (100%) rename content/photos/{2010-09-01-gdr-helvetica.md => 2010-09-01-gdr-helvetica/index.md} (86%) rename content/{media => photos/2010-12-11-iphone-coasters}/iPhone-Coasters-1-Version-2.jpg (100%) rename content/photos/{2010-12-11-iphone-coasters.md => 2010-12-11-iphone-coasters/index.md} (86%) rename content/{media => photos/2010-12-29-basically-the-monolith-is-on-my-desk}/Basically-The-Monolith-Is-On-My-Desk.jpg (100%) rename content/photos/{2010-12-29-basically-the-monolith-is-on-my-desk.md => 2010-12-29-basically-the-monolith-is-on-my-desk/index.md} (84%) rename content/{media => photos/2010-12-29-free-monkey-breath-not-soylent-green}/Free-Monkey-Breath-Not-Soylent-Green.jpg (100%) rename content/photos/{2010-12-29-free-monkey-breath-not-soylent-green.md => 2010-12-29-free-monkey-breath-not-soylent-green/index.md} (81%) rename content/{media => photos/2011-01-08-enjoying-paper}/Enjoying-Paper.jpg (100%) rename content/photos/{2011-01-08-enjoying-paper.md => 2011-01-08-enjoying-paper/index.md} (86%) rename content/{media => photos/2011-01-08-glowing-star-inside}/Glowing-Star-Inside.jpg (100%) rename content/photos/{2011-01-08-glowing-star-inside.md => 2011-01-08-glowing-star-inside/index.md} (81%) rename content/{media => photos/2011-01-18-historic-flood-levels}/Historic-Flood-Levels.jpg (100%) rename content/photos/{2011-01-18-historic-flood-levels.md => 2011-01-18-historic-flood-levels/index.md} (82%) rename content/{media => photos/2011-10-11-broken-nexus-s-screen}/Broken-Nexus-S-Screen.jpg (100%) rename content/photos/{2011-10-11-broken-nexus-s-screen.md => 2011-10-11-broken-nexus-s-screen/index.md} (86%) rename content/{media => photos/2012-03-04-relaxing-cat}/7f9397a265d811e1b9f1123138140926_7.jpg (100%) rename content/photos/{2012-03-04-relaxing-cat.md => 2012-03-04-relaxing-cat/index.md} (66%) rename content/{media => photos/2012-04-03-blaue-turme}/Blaue-Tuerme-1.jpg (100%) rename content/photos/{2012-04-03-blaue-turme.md => 2012-04-03-blaue-turme/index.md} (86%) rename content/{media => photos/2012-04-03-skeletor}/6313cc1e7db611e180c9123138016265_7.jpg (100%) rename content/photos/{2012-04-03-skeletor.md => 2012-04-03-skeletor/index.md} (50%) rename content/{media => photos/2012-04-03-train-station-leipzig}/de2ac24c7db911e1b9f1123138140926_7.jpg (100%) rename content/photos/{2012-04-03-train-station-leipzig.md => 2012-04-03-train-station-leipzig/index.md} (55%) rename content/{media => photos/2012-04-05-current-sushi-status}/aff38e2c7f5311e1b10e123138105d6b_7.jpg (100%) rename content/photos/{2012-04-05-current-sushi-status.md => 2012-04-05-current-sushi-status/index.md} (55%) delete mode 100644 content/photos/2012-04-07-buna.md rename content/{media => photos/2012-04-07-buna}/44af28f2805b11e18cf91231380fd29b_7.jpg (100%) create mode 100644 content/photos/2012-04-07-buna/index.md rename content/{media => photos/2012-04-07-cat-enjoying-a-good-ipad-game}/7838011c80ce11e19e4a12313813ffc0_7.jpg (100%) rename content/photos/{2012-04-07-cat-enjoying-a-good-ipad-game.md => 2012-04-07-cat-enjoying-a-good-ipad-game/index.md} (69%) rename content/{media => photos/2012-04-07-ipad-porn}/97a44d6080b711e181bd12313817987b_7.jpg (100%) rename content/photos/{2012-04-07-ipad-porn.md => 2012-04-07-ipad-porn/index.md} (60%) rename content/{media => photos/2012-04-07-opera}/5df6e0a280c911e1a87612313804ec91_7.jpg (100%) rename content/photos/{2012-04-07-opera.md => 2012-04-07-opera/index.md} (60%) rename content/{media => photos/2012-04-08-common-kitchen-decoration}/2ba6eeba81b111e1989612313815112c_7.jpg (100%) rename content/photos/{2012-04-08-common-kitchen-decoration.md => 2012-04-08-common-kitchen-decoration/index.md} (65%) rename content/{media => photos/2012-04-08-graffiti-old-school-style}/7e2b28f881b711e1af7612313813f8e8_7.jpg (100%) rename content/photos/{2012-04-08-graffiti-old-school-style.md => 2012-04-08-graffiti-old-school-style/index.md} (71%) rename content/{media => photos/2012-05-03-antique-chrome}/5fc688aa953811e180c9123138016265_7.jpg (100%) rename content/photos/{2012-05-03-antique-chrome.md => 2012-05-03-antique-chrome/index.md} (70%) rename content/{media/41b5a454a43811e1989612313815112c_7.jpeg => photos/2012-05-23-like-modern-heating-only-more-badass/41b5a454a43811e1989612313815112c_7.jpg} (100%) rename content/photos/{2012-05-23-like-modern-heating-only-more-badass.md => 2012-05-23-like-modern-heating-only-more-badass/index.md} (80%) rename content/{media => photos/2012-05-27-balloon}/690fe368a81911e1b2fe1231380205bf_7.jpg (100%) rename content/photos/{2012-05-27-balloon.md => 2012-05-27-balloon/index.md} (71%) rename content/{media => photos/2012-06-27-typography-window}/80a136dabff711e188131231381b5c25_7.jpg (100%) rename content/photos/{2012-06-27-typography-window.md => 2012-06-27-typography-window/index.md} (70%) rename content/{media => photos/2012-07-20-mmmmh-coffee}/66a6e0c0d25a11e1a94522000a1e8aaf_7.jpg (100%) rename content/photos/{2012-07-20-mmmmh-coffee.md => 2012-07-20-mmmmh-coffee/index.md} (66%) rename content/{media => photos/2012-08-08-amazingly-early}/2ca7a094e10f11e1868c12313817a130_7.jpg (100%) rename content/photos/{2012-08-08-amazingly-early.md => 2012-08-08-amazingly-early/index.md} (66%) rename content/{media => photos/2012-08-25-so-much-room}/c0c45b6eeea211e1ad8e22000a1cdbb8_7.jpg (100%) rename content/photos/{2012-08-25-so-much-room.md => 2012-08-25-so-much-room/index.md} (65%) rename content/{media => photos/2012-09-07-huge-station-is-huge}/619b3900f92911e1a31922000a1cddf1_7.jpg (100%) rename content/photos/{2012-09-07-huge-station-is-huge.md => 2012-09-07-huge-station-is-huge/index.md} (60%) rename content/{media => photos/2012-09-10-subway-firefox}/84f9d2c4fb7411e19ca422000a1d0119_7.jpg (100%) rename content/photos/{2012-09-10-subway-firefox.md => 2012-09-10-subway-firefox/index.md} (66%) rename content/{media => photos/2012-09-12-sweet-typography}/01f8b0b8fcc611e19b5b123138140bce_7.jpg (100%) rename content/photos/{2012-09-12-sweet-typography.md => 2012-09-12-sweet-typography/index.md} (70%) rename content/{media => photos/2012-09-14-bvg-dos}/6c4003f2fe9911e1ae9122000a1e9e21_7.jpg (100%) rename content/photos/{2012-09-14-bvg-dos.md => 2012-09-14-bvg-dos/index.md} (56%) rename content/{media => photos/2013-02-17-castle-garden}/8372983659_da0e88ca79_o.jpg (100%) rename content/photos/{2013-02-17-castle-garden.md => 2013-02-17-castle-garden/index.md} (78%) rename content/{media => photos/2013-02-17-ezeep-android-app-design}/8455835942_a9b9100373_o.jpg (100%) rename content/photos/{2013-02-17-ezeep-android-app-design.md => 2013-02-17-ezeep-android-app-design/index.md} (84%) rename content/{media => photos/2013-02-17-ezeep-office-view}/8450618380_83c64006c6_o.jpg (100%) rename content/photos/{2013-02-17-ezeep-office-view.md => 2013-02-17-ezeep-office-view/index.md} (83%) rename content/{media => photos/2013-05-23-ezeep-birds}/8776417095_43553c88c2_o.jpg (100%) rename content/photos/{2013-05-23-ezeep-birds.md => 2013-05-23-ezeep-birds/index.md} (75%) rename content/{media => photos/2013-05-23-ezeep-origami}/8782995066_e90ff6b3ae_o.jpg (100%) rename content/photos/{2013-05-23-ezeep-origami.md => 2013-05-23-ezeep-origami/index.md} (75%) rename content/photos/{2014-03-10-just-a-normal-sunday.md => 2014-03-10-just-a-normal-sunday/index.md} (52%) rename content/{media => photos/2014-03-10-just-a-normal-sunday}/just-a-normal-sunday.jpg (100%) rename content/photos/{2014-03-15-potsdam.md => 2014-03-15-potsdam/index.md} (75%) rename content/{media => photos/2014-03-15-potsdam}/potsdam.jpg (100%) rename content/photos/{2014-03-17-typographic-diamond.md => 2014-03-17-typographic-diamond/index.md} (87%) rename content/{media => photos/2014-03-17-typographic-diamond}/typographic-diamond.jpg (100%) rename content/{media => photos/2014-04-26-ai-weiwei-stools}/ai-wei-wei-stools.jpg (100%) rename content/photos/{2014-04-26-ai-weiwei-stools.md => 2014-04-26-ai-weiwei-stools/index.md} (87%) rename content/{media => photos/2014-06-07-airfield-reference-point}/airfield-reference-point.jpg (100%) rename content/photos/{2014-06-07-airfield-reference-point.md => 2014-06-07-airfield-reference-point/index.md} (85%) rename content/photos/{ => 2015-03-29-anton-henning-heimat-schaffen-simpsons}/2015-03-29-anton-henning-heimat-schaffen-simpsons.jpg (100%) rename content/photos/{2015-03-29-anton-henning-heimat-schaffen-simpsons.md => 2015-03-29-anton-henning-heimat-schaffen-simpsons/index.md} (77%) rename content/photos/{ => 2015-03-29-thanks-for-the-tip-little-orange-blob}/2015-03-29-thanks-for-the-tip-little-orange-blob.jpg (100%) rename content/photos/{2015-03-29-thanks-for-the-tip-little-orange-blob.md => 2015-03-29-thanks-for-the-tip-little-orange-blob/index.md} (67%) rename content/photos/{2015-04-09-most-surprising-dog-i-know.md => 2015-04-09-most-surprising-dog-i-know/index.md} (72%) rename content/{media => photos/2015-04-09-most-surprising-dog-i-know}/most-surprising-dog-i-know.jpg (100%) rename content/photos/{2015-04-16-obligatory-it-s-summer-in-berlin-photo.md => 2015-04-16-obligatory-it-s-summer-in-berlin-photo/index.md} (69%) rename content/{media => photos/2015-04-16-obligatory-it-s-summer-in-berlin-photo}/obligatory-it-s-summer-in-berlin-photo.jpg (100%) rename content/photos/{ => 2015-04-17-suddenly-a-new-hindu-temple-appears-around-the-corner}/2015-04-17-suddenly-a-new-hindu-temple-appears-around-the-corner.jpg (100%) rename content/photos/{2015-04-17-suddenly-a-new-hindu-temple-appears-around-the-corner.md => 2015-04-17-suddenly-a-new-hindu-temple-appears-around-the-corner/index.md} (66%) rename content/{media => photos/2015-04-23-that-moment-when-your-childhood-toys-hang-painted-in-a-gallery}/Monstrum_Gameboy_Catherine_Kaleel.jpg (100%) rename content/photos/{2015-04-23-that-moment-when-your-childhood-toys-hang-painted-in-a-gallery.md => 2015-04-23-that-moment-when-your-childhood-toys-hang-painted-in-a-gallery/index.md} (87%) rename content/photos/{2015-04-25-tiny-tiny-demons.md => 2015-04-25-tiny-tiny-demons/index.md} (75%) rename content/{media => photos/2015-04-25-tiny-tiny-demons}/tiny_tiny_demons.jpg (100%) rename content/photos/{2016-02-25-gaudi-knows-how-to-impress-with-a-ceiling.md => 2016-02-25-gaudi-knows-how-to-impress-with-a-ceiling/index.md} (68%) rename content/{media => photos/2016-02-25-gaudi-knows-how-to-impress-with-a-ceiling}/sagrada-familia-ceiling.jpg (100%) rename content/photos/{2016-02-27-streets-of-el-raval.md => 2016-02-27-streets-of-el-raval/index.md} (80%) rename content/{media => photos/2016-02-27-streets-of-el-raval}/streets-of-el-raval.jpg (100%) rename content/{media => photos/2016-03-02-a-storm-is-coming}/a-storm-is-coming.jpg (100%) rename content/photos/{2016-03-02-a-storm-is-coming.md => 2016-03-02-a-storm-is-coming/index.md} (62%) rename content/photos/{2017-02-13-keith-haring-vandalizing-a-wall.md => 2017-02-13-keith-haring-vandalizing-a-wall/index.md} (80%) rename content/{media => photos/2017-02-13-keith-haring-vandalizing-a-wall}/keith-haring-vandalizing-a-wall.jpg (100%) rename content/photos/{2017-02-13-streets-of-el-born.md => 2017-02-13-streets-of-el-born/index.md} (79%) rename content/{media => photos/2017-02-13-streets-of-el-born}/streets-of-el-born.jpg (100%) rename content/photos/{2017-02-14-new-passion-facade.md => 2017-02-14-new-passion-facade/index.md} (90%) rename content/{media => photos/2017-02-14-new-passion-facade}/new-passion-facade.jpg (100%) rename content/{media => photos/2017-02-16-coolhaven-rotterdam}/coolhaven-rotterdam.jpg (100%) rename content/photos/{2017-02-16-coolhaven-rotterdam.md => 2017-02-16-coolhaven-rotterdam/index.md} (64%) rename content/{media => photos/2017-02-17-behind-the-art}/behind-the-art.jpg (100%) rename content/photos/{2017-02-17-behind-the-art.md => 2017-02-17-behind-the-art/index.md} (66%) rename content/photos/{ => 2017-02-19-rotterdam-coats}/2017-02-19-rotterdam-coats.jpg (100%) rename content/photos/{2017-02-19-rotterdam-coats.md => 2017-02-19-rotterdam-coats/index.md} (85%) rename content/photos/{ => 2017-02-21-david-chipperfield-staircase}/2017-02-21-david-chipperfield-staircase.jpg (100%) rename content/photos/{2017-02-21-david-chipperfield-staircase.md => 2017-02-21-david-chipperfield-staircase/index.md} (82%) rename content/photos/{ => 2017-02-26-eu-gotham-city}/2017-02-26-eu-gotham-city.jpg (100%) rename content/photos/{2017-02-26-eu-gotham-city.md => 2017-02-26-eu-gotham-city/index.md} (85%) rename content/photos/{ => 2017-02-27-amsterdam-cliche}/2017-02-27-amsterdam-cliche.jpg (100%) rename content/photos/{2017-02-27-amsterdam-cliche.md => 2017-02-27-amsterdam-cliche/index.md} (85%) rename content/photos/{ => 2017-02-27-its-dark-and-i-dont-exist}/2017-02-27-its-dark-and-i-dont-exist.jpg (100%) rename content/photos/{2017-02-27-its-dark-and-i-dont-exist.md => 2017-02-27-its-dark-and-i-dont-exist/index.md} (73%) rename content/photos/{ => 2017-02-28-stedelijk-museum}/2017-02-28-stedelijk-museum.jpg (100%) rename content/photos/{2017-02-28-stedelijk-museum.md => 2017-02-28-stedelijk-museum/index.md} (78%) rename content/photos/{ => 2017-02-28-temple-guardian-rijksmuseum}/2017-02-28-temple-guardian-rijksmuseum.jpg (100%) rename content/photos/{2017-02-28-temple-guardian-rijksmuseum.md => 2017-02-28-temple-guardian-rijksmuseum/index.md} (84%) rename content/photos/{ => 2017-02-28-watching-the-night-watch}/2017-02-28-watching-the-night-watch.jpg (100%) rename content/photos/{2017-02-28-watching-the-night-watch.md => 2017-02-28-watching-the-night-watch/index.md} (82%) rename content/photos/{ => 2017-04-16-hamburgs-elbphilharmonie}/2017-04-16-hamburgs-elbphilharmonie.jpg (100%) rename content/photos/{2017-04-16-hamburgs-elbphilharmonie.md => 2017-04-16-hamburgs-elbphilharmonie/index.md} (80%) rename content/photos/{ => 2017-04-29-palace-scaffolding}/2017-04-29-palace-scaffolding.jpg (100%) rename content/photos/{2017-04-29-palace-scaffolding.md => 2017-04-29-palace-scaffolding/index.md} (78%) rename content/photos/{ => 2017-07-05-kapaleeshwarar-temple-chennai}/2017-07-05-kapaleeshwarar-temple-chennai.jpg (100%) rename content/photos/{2017-07-05-kapaleeshwarar-temple-chennai.md => 2017-07-05-kapaleeshwarar-temple-chennai/index.md} (79%) rename content/photos/{ => 2017-07-08-kochis-streetart-game-is-strong}/2017-07-08-kochis-streetart-game-is-strong.jpg (100%) rename content/photos/{2017-07-08-kochis-streetart-game-is-strong.md => 2017-07-08-kochis-streetart-game-is-strong/index.md} (81%) rename content/photos/{ => 2017-07-09-orphaned-elephant-with-friend}/2017-07-09-orphaned-elephant-with-friend.jpg (100%) rename content/photos/{2017-07-09-orphaned-elephant-with-friend.md => 2017-07-09-orphaned-elephant-with-friend/index.md} (78%) rename content/photos/{ => 2017-07-10-kochis-dhobhi-ghat}/2017-07-10-kochis-dhobhi-ghat.jpg (100%) rename content/photos/{2017-07-10-kochis-dhobhi-ghat.md => 2017-07-10-kochis-dhobhi-ghat/index.md} (85%) rename content/photos/{ => 2017-07-13-mumbai-hand-painted-typography}/2017-07-13-mumbai-hand-painted-typography.jpg (100%) rename content/photos/{2017-07-13-mumbai-hand-painted-typography.md => 2017-07-13-mumbai-hand-painted-typography/index.md} (83%) rename content/photos/{ => 2017-07-13-obligatory-gate-of-india-photo}/2017-07-13-obligatory-gate-of-india-photo.jpg (100%) rename content/photos/{2017-07-13-obligatory-gate-of-india-photo.md => 2017-07-13-obligatory-gate-of-india-photo/index.md} (79%) rename content/photos/{ => 2017-07-14-chhatrapati-shivaji-maharaj-vastu-sangrahalaya}/2017-07-14-chhatrapati-shivaji-maharaj-vastu-sangrahalaya.jpg (100%) rename content/photos/{2017-07-14-chhatrapati-shivaji-maharaj-vastu-sangrahalaya.md => 2017-07-14-chhatrapati-shivaji-maharaj-vastu-sangrahalaya/index.md} (82%) rename content/photos/{ => 2017-11-10-acropolis-the-erechtheum}/2017-11-10-acropolis-the-erechtheum.jpg (100%) rename content/photos/{2017-11-10-acropolis-the-erechtheum.md => 2017-11-10-acropolis-the-erechtheum/index.md} (79%) rename content/photos/{ => 2017-11-10-acropolis-the-parthenon}/2017-11-10-acropolis-the-parthenon.jpg (100%) rename content/photos/{2017-11-10-acropolis-the-parthenon.md => 2017-11-10-acropolis-the-parthenon/index.md} (79%) rename content/photos/{ => 2017-11-10-acropolis-the-propylaea}/2017-11-10-acropolis-the-propylaea.jpg (100%) rename content/photos/{2017-11-10-acropolis-the-propylaea.md => 2017-11-10-acropolis-the-propylaea/index.md} (80%) rename content/photos/{ => 2017-12-15-el-born-centre-de-cultura-i-memoria}/2017-12-15-el-born-centre-de-cultura-i-memoria.jpg (100%) rename content/photos/{2017-12-15-el-born-centre-de-cultura-i-memoria.md => 2017-12-15-el-born-centre-de-cultura-i-memoria/index.md} (75%) rename content/photos/{ => 2017-12-16-sagrada-familia}/2017-12-16-sagrada-familia.jpg (100%) rename content/photos/{2017-12-16-sagrada-familia.md => 2017-12-16-sagrada-familia/index.md} (74%) rename content/photos/{ => 2017-12-27-sao-paulo-traffic}/2017-12-27-sao-paulo-traffic.jpg (100%) rename content/photos/{2017-12-27-sao-paulo-traffic.md => 2017-12-27-sao-paulo-traffic/index.md} (73%) rename content/photos/{ => 2018-01-04-passagem-literaria-da-consolacao}/2018-01-04-passagem-literaria-da-consolacao.jpg (100%) rename content/photos/{2018-01-04-passagem-literaria-da-consolacao.md => 2018-01-04-passagem-literaria-da-consolacao/index.md} (72%) rename content/photos/{ => 2018-01-05-samba-school}/2018-01-05-samba-school.jpg (100%) rename content/photos/{2018-01-05-samba-school.md => 2018-01-05-samba-school/index.md} (74%) rename content/photos/{ => 2018-01-10-smoking-death}/2018-01-10-smoking-death.jpg (100%) rename content/photos/{2018-01-10-smoking-death.md => 2018-01-10-smoking-death/index.md} (78%) rename content/photos/{ => 2018-01-13-teatro-jaragua}/2018-01-13-teatro-jaragua.jpg (100%) rename content/photos/{2018-01-13-teatro-jaragua.md => 2018-01-13-teatro-jaragua/index.md} (78%) rename content/photos/{ => 2018-01-15-a-revolucao-nao-sera-televisionada}/2018-01-15-a-revolucao-nao-sera-televisionada.jpg (100%) rename content/photos/{2018-01-15-a-revolucao-nao-sera-televisionada.md => 2018-01-15-a-revolucao-nao-sera-televisionada/index.md} (68%) rename content/photos/{ => 2018-01-15-fusca-e-pichacao}/2018-01-15-fusca-e-pichacao.jpg (100%) rename content/photos/{2018-01-15-fusca-e-pichacao.md => 2018-01-15-fusca-e-pichacao/index.md} (67%) rename content/photos/{ => 2018-01-17-boa-viagem}/2018-01-17-boa-viagem.jpg (100%) rename content/photos/{2018-01-17-boa-viagem.md => 2018-01-17-boa-viagem/index.md} (71%) rename content/photos/{ => 2018-01-17-instituto-ricardo-brennand}/2018-01-17-instituto-ricardo-brennand.jpg (100%) rename content/photos/{2018-01-17-instituto-ricardo-brennand.md => 2018-01-17-instituto-ricardo-brennand/index.md} (76%) rename content/photos/{ => 2018-01-24-avenida-paulista-i}/2018-01-24-avenida-paulista-i.jpg (100%) rename content/photos/{2018-01-24-avenida-paulista-i.md => 2018-01-24-avenida-paulista-i/index.md} (70%) rename content/photos/{ => 2018-01-25-avenida-paulista-ii}/2018-01-25-avenida-paulista-ii.jpg (100%) rename content/photos/{2018-01-25-avenida-paulista-ii.md => 2018-01-25-avenida-paulista-ii/index.md} (80%) rename content/photos/{ => 2018-01-26-auditorio-ibirapuera}/2018-01-26-auditorio-ibirapuera.jpg (100%) rename content/photos/{2018-01-26-auditorio-ibirapuera.md => 2018-01-26-auditorio-ibirapuera/index.md} (84%) rename content/photos/{ => 2018-01-26-oca-do-ibirapuera-i}/2018-01-26-oca-do-ibirapuera-i.jpg (100%) rename content/photos/{2018-01-26-oca-do-ibirapuera-i.md => 2018-01-26-oca-do-ibirapuera-i/index.md} (87%) rename content/photos/{ => 2018-01-26-oca-do-ibirapuera-ii}/2018-01-26-oca-do-ibirapuera-ii.jpg (100%) rename content/photos/{2018-01-26-oca-do-ibirapuera-ii.md => 2018-01-26-oca-do-ibirapuera-ii/index.md} (87%) rename content/photos/{ => 2018-01-26-pavilhao-das-culturas-brasileiras}/2018-01-26-pavilhao-das-culturas-brasileiras.jpg (100%) rename content/photos/{2018-01-26-pavilhao-das-culturas-brasileiras.md => 2018-01-26-pavilhao-das-culturas-brasileiras/index.md} (83%) rename content/photos/{ => 2018-02-24-muzeul-national-de-arta-al-romaniei}/2018-02-24-muzeul-national-de-arta-al-romaniei.jpg (100%) rename content/photos/{2018-02-24-muzeul-national-de-arta-al-romaniei.md => 2018-02-24-muzeul-national-de-arta-al-romaniei/index.md} (77%) rename content/photos/{ => 2018-02-25-muzeul-national-de-istorie-a-romaniei}/2018-02-25-muzeul-national-de-istorie-a-romaniei.jpg (100%) rename content/photos/{2018-02-25-muzeul-national-de-istorie-a-romaniei.md => 2018-02-25-muzeul-national-de-istorie-a-romaniei/index.md} (78%) rename content/photos/{ => 2018-05-01-may-day-kreuzberg}/2018-05-01-may-day-kreuzberg.jpg (100%) rename content/photos/{2018-05-01-may-day-kreuzberg.md => 2018-05-01-may-day-kreuzberg/index.md} (80%) rename content/photos/{ => 2018-06-01-roger-waters-us-them}/2018-06-01-roger-waters-us-them.jpg (100%) rename content/photos/{2018-06-01-roger-waters-us-them.md => 2018-06-01-roger-waters-us-them/index.md} (71%) rename content/photos/{ => 2018-07-02-nine-inch-nails-zitadelle}/2018-07-02-nine-inch-nails-zitadelle.jpg (100%) rename content/photos/{2018-07-02-nine-inch-nails-zitadelle.md => 2018-07-02-nine-inch-nails-zitadelle/index.md} (72%) rename content/photos/{ => 2018-09-01-stasi-museum}/2018-09-01-stasi-museum.jpg (100%) rename content/photos/{2018-09-01-stasi-museum.md => 2018-09-01-stasi-museum/index.md} (74%) rename content/photos/{ => 2018-12-26-elevador-de-santa-justa}/2018-12-26-elevador-de-santa-justa.jpg (100%) rename content/photos/{2018-12-26-elevador-de-santa-justa.md => 2018-12-26-elevador-de-santa-justa/index.md} (63%) rename content/photos/{ => 2018-12-27-palacio-nacional-da-pena}/2018-12-27-palacio-nacional-da-pena.jpg (100%) rename content/photos/{2018-12-27-palacio-nacional-da-pena.md => 2018-12-27-palacio-nacional-da-pena/index.md} (73%) rename content/photos/{ => 2018-12-27-rua-da-prata}/2018-12-27-rua-da-prata.jpg (100%) rename content/photos/{2018-12-27-rua-da-prata.md => 2018-12-27-rua-da-prata/index.md} (63%) rename content/photos/{ => 2018-12-29-gare-do-oriente}/2018-12-29-gare-do-oriente.jpg (100%) rename content/photos/{2018-12-29-gare-do-oriente.md => 2018-12-29-gare-do-oriente/index.md} (79%) rename content/photos/{ => 2019-01-27-all-work-and-no-play}/2019-01-27-all-work-and-no-play.jpg (100%) rename content/photos/{2019-01-27-all-work-and-no-play.md => 2019-01-27-all-work-and-no-play/index.md} (86%) rename content/photos/{ => 2019-02-25-edificio-italia}/2019-02-25-edificio-italia.jpg (100%) rename content/photos/{2019-02-25-edificio-italia.md => 2019-02-25-edificio-italia/index.md} (76%) rename content/photos/{ => 2019-03-06-brazilian-museum-of-sculpture-and-ecology}/2019-03-06-brazilian-museum-of-sculpture-and-ecology.jpg (100%) rename content/photos/{2019-03-06-brazilian-museum-of-sculpture-and-ecology.md => 2019-03-06-brazilian-museum-of-sculpture-and-ecology/index.md} (73%) rename content/photos/{ => 2019-03-13-paraty-mirim}/2019-03-13-paraty-mirim.jpg (100%) rename content/photos/{2019-03-13-paraty-mirim.md => 2019-03-13-paraty-mirim/index.md} (76%) rename content/photos/{ => 2019-03-18-catedral-da-se-de-sao-paulo}/2019-03-18-catedral-da-se-de-sao-paulo.jpg (100%) rename content/photos/{2019-03-18-catedral-da-se-de-sao-paulo.md => 2019-03-18-catedral-da-se-de-sao-paulo/index.md} (81%) rename content/photos/{ => 2019-08-18-german-chancellery-ii}/2019-08-18-german-chancellery-ii.jpg (100%) rename content/photos/{2019-08-18-german-chancellery-ii.md => 2019-08-18-german-chancellery-ii/index.md} (73%) rename content/photos/{ => 2019-09-28-vatican-museums}/2019-09-28-vatican-museums.jpg (100%) rename content/photos/{2019-09-28-vatican-museums.md => 2019-09-28-vatican-museums/index.md} (80%) rename content/photos/{ => 2019-09-29-arco-di-costantino}/2019-09-29-arco-di-costantino.jpg (100%) rename content/photos/{2019-09-29-arco-di-costantino.md => 2019-09-29-arco-di-costantino/index.md} (76%) rename content/photos/{ => 2019-09-29-foro-di-cesare}/2019-09-29-foro-di-cesare.jpg (100%) rename content/photos/{2019-09-29-foro-di-cesare.md => 2019-09-29-foro-di-cesare/index.md} (85%) rename content/photos/{ => 2019-11-02-orszaghaz-i}/2019-11-02-orszaghaz-i.jpg (100%) rename content/photos/{2019-11-02-orszaghaz-i.md => 2019-11-02-orszaghaz-i/index.md} (80%) rename content/photos/{ => 2019-11-03-orszaghaz-ii}/2019-11-03-orszaghaz-ii.jpg (100%) rename content/photos/{2019-11-03-orszaghaz-ii.md => 2019-11-03-orszaghaz-ii/index.md} (77%) rename content/photos/{ => 2019-11-03-orszaghaz-iii}/2019-11-03-orszaghaz-iii.jpg (100%) rename content/photos/{2019-11-03-orszaghaz-iii.md => 2019-11-03-orszaghaz-iii/index.md} (76%) rename content/photos/{ => 2019-11-16-helmut-newton-foundation}/2019-11-16-helmut-newton-foundation.jpg (100%) rename content/photos/{2019-11-16-helmut-newton-foundation.md => 2019-11-16-helmut-newton-foundation/index.md} (85%) rename content/photos/{ => 2020-01-05-raw-gelande}/2020-01-05-raw-gelande.jpg (100%) rename content/photos/{2020-01-05-raw-gelande.md => 2020-01-05-raw-gelande/index.md} (85%) rename content/photos/{ => 2020-01-17-balloon-dog}/2020-01-17-balloon-dog.jpg (100%) rename content/photos/{2020-01-17-balloon-dog.md => 2020-01-17-balloon-dog/index.md} (85%) rename content/photos/{ => 2020-01-17-bremen-cathedral}/2020-01-17-bremen-cathedral.jpg (100%) rename content/photos/{2020-01-17-bremen-cathedral.md => 2020-01-17-bremen-cathedral/index.md} (82%) rename content/photos/{ => 2020-06-14-x-marks-the-spot}/2020-06-14-x-marks-the-spot.jpg (100%) rename content/photos/{2020-06-14-x-marks-the-spot.md => 2020-06-14-x-marks-the-spot/index.md} (77%) rename content/photos/{ => 2020-06-28-lines-of-nature}/2020-06-28-lines-of-nature.jpg (100%) rename content/photos/{2020-06-28-lines-of-nature.md => 2020-06-28-lines-of-nature/index.md} (61%) rename content/photos/{ => 2020-08-13-2020}/2020-08-13-2020.jpg (100%) rename content/photos/{2020-08-13-2020.md => 2020-08-13-2020/index.md} (65%) rename content/photos/{ => 2020-08-16-castle-gardens}/2020-08-16-castle-gardens.jpg (100%) rename content/photos/{2020-08-16-castle-gardens.md => 2020-08-16-castle-gardens/index.md} (79%) rename content/photos/{ => 2020-09-12-friedrichshain}/2020-09-12-friedrichshain.jpg (100%) rename content/photos/{2020-09-12-friedrichshain.md => 2020-09-12-friedrichshain/index.md} (61%) rename content/photos/{ => 2020-10-11-charite}/2020-10-11-charite.jpg (100%) rename content/photos/{2020-10-11-charite.md => 2020-10-11-charite/index.md} (77%) rename content/photos/{ => 2020-10-25-letters-change}/2020-10-25-letters-change.jpg (100%) rename content/photos/{2020-10-25-letters-change.md => 2020-10-25-letters-change/index.md} (81%) rename content/photos/{ => 2020-11-29-wall-memorial}/2020-11-29-wall-memorial.jpg (100%) rename content/photos/{2020-11-29-wall-memorial.md => 2020-11-29-wall-memorial/index.md} (73%) rename content/photos/{ => 2020-12-22-tier-pandemic}/2020-12-22-tier-pandemic.jpg (100%) rename content/photos/{2020-12-22-tier-pandemic.md => 2020-12-22-tier-pandemic/index.md} (73%) rename content/photos/{ => 2021-02-21-reflections}/2021-02-21-reflections.jpg (100%) rename content/photos/{2021-02-21-reflections.md => 2021-02-21-reflections/index.md} (79%) rename content/photos/{ => 2021-07-07-museum-neuruppin-staircase}/2021-07-07-museum-neuruppin-staircase.jpg (100%) rename content/photos/{2021-07-07-museum-neuruppin-staircase.md => 2021-07-07-museum-neuruppin-staircase/index.md} (76%) rename content/photos/{ => 2021-08-05-maidan-nezalezhnosti}/2021-08-05-maidan-nezalezhnosti.jpg (100%) rename content/photos/{2021-08-05-maidan-nezalezhnosti.md => 2021-08-05-maidan-nezalezhnosti/index.md} (82%) rename content/photos/{ => 2021-08-06-hram-arhistratiga-mihayila-ta-ukrayinskih-novomuchenikiv}/2021-08-06-hram-arhistratiga-mihayila-ta-ukrayinskih-novomuchenikiv.jpg (100%) rename content/photos/{2021-08-06-hram-arhistratiga-mihayila-ta-ukrayinskih-novomuchenikiv.md => 2021-08-06-hram-arhistratiga-mihayila-ta-ukrayinskih-novomuchenikiv/index.md} (84%) rename content/photos/{ => 2021-08-08-kyiv-funicular}/2021-08-08-kyiv-funicular.jpg (100%) rename content/photos/{2021-08-08-kyiv-funicular.md => 2021-08-08-kyiv-funicular/index.md} (80%) rename content/photos/{ => 2021-08-08-kyiv-underground}/2021-08-08-kyiv-underground.jpg (100%) rename content/photos/{2021-08-08-kyiv-underground.md => 2021-08-08-kyiv-underground/index.md} (60%) rename content/photos/{ => 2021-08-09-kiyiv-pasazhirskij}/2021-08-09-kiyiv-pasazhirskij.jpg (100%) rename content/photos/{2021-08-09-kiyiv-pasazhirskij.md => 2021-08-09-kiyiv-pasazhirskij/index.md} (65%) rename content/photos/{ => 2021-08-17-horticya}/2021-08-17-horticya.jpg (100%) rename content/photos/{2021-08-17-horticya.md => 2021-08-17-horticya/index.md} (90%) rename content/photos/{ => 2021-08-17-zaporizhzhya}/2021-08-17-zaporizhzhya.jpg (100%) rename content/photos/{2021-08-17-zaporizhzhya.md => 2021-08-17-zaporizhzhya/index.md} (81%) rename content/photos/{ => 2021-09-26-arc-de-triomphe-wrapped}/2021-09-26-arc-de-triomphe-wrapped.jpg (100%) rename content/photos/{2021-09-26-arc-de-triomphe-wrapped.md => 2021-09-26-arc-de-triomphe-wrapped/index.md} (79%) rename content/photos/{ => 2021-09-26-centre-pompidou-pigeons}/2021-09-26-centre-pompidou-pigeons.jpg (100%) rename content/photos/{2021-09-26-centre-pompidou-pigeons.md => 2021-09-26-centre-pompidou-pigeons/index.md} (76%) rename content/photos/{ => 2021-09-26-louvre-i}/2021-09-26-louvre-i.jpg (100%) rename content/photos/{2021-09-26-louvre-i.md => 2021-09-26-louvre-i/index.md} (62%) rename content/photos/{ => 2021-09-26-tour-eiffel}/2021-09-26-tour-eiffel.jpg (100%) rename content/photos/{2021-09-26-tour-eiffel.md => 2021-09-26-tour-eiffel/index.md} (81%) rename content/photos/{ => 2021-09-29-louvre-ii}/2021-09-29-louvre-ii.jpg (100%) rename content/photos/{2021-09-29-louvre-ii.md => 2021-09-29-louvre-ii/index.md} (62%) rename content/photos/{ => 2021-09-30-tgv-euroduplex}/2021-09-30-tgv-euroduplex.jpg (100%) rename content/photos/{2021-09-30-tgv-euroduplex.md => 2021-09-30-tgv-euroduplex/index.md} (85%) rename content/photos/{ => 2021-10-04-santa-maria-la-real-de-la-almudena}/2021-10-04-santa-maria-la-real-de-la-almudena.jpg (100%) rename content/photos/{2021-10-04-santa-maria-la-real-de-la-almudena.md => 2021-10-04-santa-maria-la-real-de-la-almudena/index.md} (77%) rename content/photos/{ => 2021-10-09-ponte-da-arrabida}/2021-10-09-ponte-da-arrabida.jpg (100%) rename content/photos/{2021-10-09-ponte-da-arrabida.md => 2021-10-09-ponte-da-arrabida/index.md} (79%) rename content/photos/{ => 2021-10-11-garagem}/2021-10-11-garagem.jpg (100%) rename content/photos/{2021-10-11-garagem.md => 2021-10-11-garagem/index.md} (63%) rename content/photos/{ => 2021-10-12-ponte-de-dom-luis-i}/2021-10-12-ponte-de-dom-luis-i.jpg (100%) rename content/photos/{2021-10-12-ponte-de-dom-luis-i.md => 2021-10-12-ponte-de-dom-luis-i/index.md} (80%) rename content/photos/{ => 2021-10-14-lince-iberico}/2021-10-14-lince-iberico.jpg (100%) rename content/photos/{2021-10-14-lince-iberico.md => 2021-10-14-lince-iberico/index.md} (82%) rename content/photos/{ => 2021-10-16-gare-do-oriente-ii}/2021-10-16-gare-do-oriente-ii.jpg (100%) rename content/photos/{2021-10-16-gare-do-oriente-ii.md => 2021-10-16-gare-do-oriente-ii/index.md} (91%) rename content/photos/{ => 2021-10-17-maat}/2021-10-17-maat.jpg (100%) rename content/photos/{2021-10-17-maat.md => 2021-10-17-maat/index.md} (84%) rename content/photos/{ => 2021-10-17-padrao-dos-descobrimentos}/2021-10-17-padrao-dos-descobrimentos.jpg (100%) rename content/photos/{2021-10-17-padrao-dos-descobrimentos.md => 2021-10-17-padrao-dos-descobrimentos/index.md} (81%) rename content/photos/{ => 2021-10-17-ponte-25-de-abril}/2021-10-17-ponte-25-de-abril.jpg (100%) rename content/photos/{2021-10-17-ponte-25-de-abril.md => 2021-10-17-ponte-25-de-abril/index.md} (83%) rename content/photos/{ => 2021-10-17-shiny-colonialism}/2021-10-17-shiny-colonialism.jpg (100%) rename content/photos/{2021-10-17-shiny-colonialism.md => 2021-10-17-shiny-colonialism/index.md} (85%) rename content/photos/{ => 2021-10-23-santuario-de-cristo-rei}/2021-10-23-santuario-de-cristo-rei.jpg (100%) rename content/photos/{2021-10-23-santuario-de-cristo-rei.md => 2021-10-23-santuario-de-cristo-rei/index.md} (80%) rename content/photos/{ => 2021-10-29-ponte-vasco-da-gama}/2021-10-29-ponte-vasco-da-gama.jpg (100%) rename content/photos/{2021-10-29-ponte-vasco-da-gama.md => 2021-10-29-ponte-vasco-da-gama/index.md} (84%) rename content/photos/{ => 2021-10-31-sagrada-familia-ii}/2021-10-31-sagrada-familia-ii.jpg (100%) rename content/photos/{2021-10-31-sagrada-familia-ii.md => 2021-10-31-sagrada-familia-ii/index.md} (88%) rename content/photos/{ => 2021-11-06-mae-d-agua}/2021-11-06-mae-d-agua.jpg (100%) rename content/photos/{2021-11-06-mae-d-agua.md => 2021-11-06-mae-d-agua/index.md} (88%) rename content/photos/{ => 2021-11-21-assembleia-da-republica}/2021-11-21-assembleia-da-republica.jpg (100%) rename content/photos/{2021-11-21-assembleia-da-republica.md => 2021-11-21-assembleia-da-republica/index.md} (85%) rename content/photos/{ => 2021-11-25-praca-do-comercio}/2021-11-25-praca-do-comercio.jpg (100%) rename content/photos/{2021-11-25-praca-do-comercio.md => 2021-11-25-praca-do-comercio/index.md} (87%) rename content/photos/{ => 2021-11-26-forever-bicycles}/2021-11-26-forever-bicycles.jpg (100%) rename content/photos/{2021-11-26-forever-bicycles.md => 2021-11-26-forever-bicycles/index.md} (89%) rename content/photos/{ => 2021-11-26-law-of-the-journey}/2021-11-26-law-of-the-journey.jpg (100%) rename content/photos/{2021-11-26-law-of-the-journey.md => 2021-11-26-law-of-the-journey/index.md} (92%) delete mode 100644 gatsby-browser.tsx delete mode 100644 gatsby-config.ts delete mode 100644 gatsby-node.ts delete mode 100644 gatsby-ssr.tsx delete mode 100644 gatsby/algolia.ts delete mode 100644 gatsby/createExif.ts delete mode 100644 gatsby/createMarkdownFields.ts delete mode 100644 gatsby/createPages.ts delete mode 100644 gatsby/feeds.ts delete mode 100644 gatsby/sources.ts rename {static => public}/robots.txt (77%) rename {static => public}/sw.js (100%) create mode 100644 scripts/create-icons/Props.d.ts create mode 100644 scripts/create-icons/index.test.ts create mode 100644 scripts/create-icons/index.ts create mode 100644 scripts/create-icons/svg.ts create mode 100755 scripts/create-symlinks.sh create mode 100644 scripts/move-downloads.test.ts create mode 100644 scripts/move-downloads.ts delete mode 100644 scripts/new.ts create mode 100644 scripts/new/createArticlePost.ts create mode 100644 scripts/new/createPhotoPost.ts create mode 100644 scripts/new/index.test.ts create mode 100644 scripts/new/index.ts rename scripts/{ => new}/new-article.md (70%) rename scripts/{ => new}/new-photo.md (53%) create mode 100644 scripts/redirect-from.test.ts create mode 100644 scripts/redirect-from.ts delete mode 100644 src/@types/Image.d.ts delete mode 100644 src/@types/Post.d.ts delete mode 100644 src/@types/css.d.ts rename src/@types/{node_modules.d.ts => dmsdec/index.d.ts} (63%) create mode 100644 src/@types/node-iptc/index.d.ts create mode 100644 src/components/BackButton.astro create mode 100644 src/components/Changelog/index.astro rename src/components/{atoms/Changelog.module.css => Changelog/index.module.css} (81%) create mode 100644 src/components/Copy.astro rename src/components/{atoms => }/Divider.module.css (85%) create mode 100644 src/components/Donation/Coin.astro create mode 100644 src/components/Donation/Web3.tsx rename src/components/{molecules => Donation}/Web3Donation/Alert.module.css (100%) rename src/components/{molecules => Donation}/Web3Donation/Alert.test.tsx (88%) rename src/components/{molecules => Donation}/Web3Donation/Alert.tsx (83%) rename src/components/{molecules => Donation}/Web3Donation/Conversion.module.css (72%) rename src/components/{molecules => Donation}/Web3Donation/Conversion.test.tsx (66%) rename src/components/{molecules => Donation}/Web3Donation/Conversion.tsx (61%) rename src/components/{molecules => Donation}/Web3Donation/InputGroup.module.css (95%) create mode 100644 src/components/Donation/Web3Donation/InputGroup.test.tsx rename src/components/{molecules => Donation}/Web3Donation/InputGroup.tsx (59%) rename src/components/{molecules => Donation}/Web3Donation/index.module.css (77%) create mode 100644 src/components/Donation/Web3Donation/index.test.tsx rename src/components/{molecules => Donation}/Web3Donation/index.tsx (70%) create mode 100644 src/components/Exif/ExifData.astro create mode 100644 src/components/Exif/ExifMap.test.tsx create mode 100644 src/components/Exif/ExifMap.tsx create mode 100644 src/components/Exif/index.astro rename src/components/{atoms/Exif.module.css => Exif/index.module.css} (89%) create mode 100644 src/components/Footer/Networks.astro rename src/components/{molecules => Footer}/Networks.module.css (100%) create mode 100644 src/components/Footer/Vcard.astro rename src/components/{molecules => Footer}/Vcard.module.css (66%) create mode 100644 src/components/Footer/index.astro rename src/components/{organisms/Footer.module.css => Footer/index.module.css} (100%) create mode 100644 src/components/Hamburger.astro create mode 100644 src/components/Header/index.astro rename src/components/{organisms/Header.module.css => Header/index.module.css} (96%) rename src/components/{atoms/Input.module.css => Input/index.module.css} (93%) create mode 100644 src/components/Input/index.test.tsx rename src/components/{atoms/Input.tsx => Input/index.tsx} (64%) delete mode 100644 src/components/Layout.test.tsx delete mode 100644 src/components/Layout.tsx create mode 100644 src/components/Menu/index.astro rename src/components/{molecules/Menu.module.css => Menu/index.module.css} (93%) create mode 100644 src/components/More.astro create mode 100644 src/components/Pagination/PageNumber.astro create mode 100644 src/components/Pagination/PrevNext.astro create mode 100644 src/components/Pagination/index.astro rename src/components/{molecules/Pagination.module.css => Pagination/index.module.css} (97%) create mode 100644 src/components/PhotoTeaser.astro create mode 100644 src/components/Picture/index.astro rename src/components/{atoms/Image.module.css => Picture/index.module.css} (77%) create mode 100644 src/components/PostTeaser/index.astro rename src/components/{molecules/PostTeaser.module.css => PostTeaser/index.module.css} (78%) create mode 100644 src/components/RelatedPosts/index.astro rename src/components/{molecules/RelatedPosts.module.css => RelatedPosts/index.module.css} (84%) rename src/components/{molecules/Search/SearchResultsEmpty.module.css => Search/Results/Empty.module.css} (100%) rename src/components/{molecules/Search/SearchResultsEmpty.tsx => Search/Results/Empty.tsx} (50%) rename src/components/{molecules/Search/SearchResults.module.css => Search/Results/index.module.css} (70%) create mode 100644 src/components/Search/Results/index.tsx rename src/components/{molecules/Search/SearchInput.module.css => Search/Search.module.css} (66%) create mode 100644 src/components/Search/Search.test.tsx create mode 100644 src/components/Search/Search.tsx create mode 100644 src/components/Search/index.astro create mode 100644 src/components/Tag.astro create mode 100644 src/components/ThemeSwitch/index.astro rename src/components/{molecules/ThemeSwitch.module.css => ThemeSwitch/index.module.css} (91%) create mode 100644 src/components/ThemeSwitch/theme.cjs create mode 100644 src/components/ThemeSwitch/theme.test.ts create mode 100644 src/components/Time.astro create mode 100644 src/components/Toc.astro delete mode 100644 src/components/atoms/Changelog.test.tsx delete mode 100644 src/components/atoms/Changelog.tsx delete mode 100644 src/components/atoms/Copy.module.css delete mode 100644 src/components/atoms/Copy.test.tsx delete mode 100644 src/components/atoms/Copy.tsx delete mode 100644 src/components/atoms/Exif.test.tsx delete mode 100644 src/components/atoms/Exif.tsx delete mode 100644 src/components/atoms/ExifMap.tsx delete mode 100644 src/components/atoms/Hamburger.module.css delete mode 100644 src/components/atoms/Hamburger.tsx delete mode 100644 src/components/atoms/HeadMeta/SchemaOrg.tsx delete mode 100644 src/components/atoms/HeadMeta/index.tsx delete mode 100644 src/components/atoms/Icon.module.css delete mode 100644 src/components/atoms/Icon.test.tsx delete mode 100644 src/components/atoms/Icon.tsx delete mode 100644 src/components/atoms/Image.tsx delete mode 100644 src/components/atoms/Input.test.tsx delete mode 100644 src/components/atoms/Tag.module.css delete mode 100644 src/components/atoms/Tag.tsx delete mode 100644 src/components/atoms/Time.tsx delete mode 100644 src/components/atoms/Transitions.ts delete mode 100644 src/components/atoms/Typekit.tsx create mode 100644 src/components/layouts/Archive.astro create mode 100644 src/components/layouts/Base/Head.astro create mode 100644 src/components/layouts/Base/SchemaOrg.astro create mode 100644 src/components/layouts/Base/index.astro rename src/components/{Layout.module.css => layouts/Base/index.module.css} (75%) create mode 100644 src/components/layouts/Post/Action.astro create mode 100644 src/components/layouts/Post/Actions.astro create mode 100644 src/components/layouts/Post/Actions.module.css create mode 100644 src/components/layouts/Post/Date.astro create mode 100644 src/components/layouts/Post/LinkActions.astro rename src/components/{templates => layouts}/Post/LinkActions.module.css (91%) create mode 100644 src/components/layouts/Post/Meta.astro rename src/components/{templates => layouts}/Post/Meta.module.css (100%) create mode 100644 src/components/layouts/Post/PrevNext.astro rename src/components/{templates => layouts}/Post/PrevNext.module.css (100%) create mode 100644 src/components/layouts/Post/Title.astro rename src/components/{templates => layouts}/Post/Title.module.css (85%) create mode 100644 src/components/layouts/Post/index.astro create mode 100644 src/components/layouts/Post/index.module.css delete mode 100644 src/components/molecules/Menu.tsx delete mode 100644 src/components/molecules/Networks.test.tsx delete mode 100644 src/components/molecules/Networks.tsx delete mode 100644 src/components/molecules/Pagination.tsx delete mode 100644 src/components/molecules/PostDate.module.css delete mode 100644 src/components/molecules/PostDate.tsx delete mode 100644 src/components/molecules/PostTeaser.test.tsx delete mode 100644 src/components/molecules/PostTeaser.tsx delete mode 100644 src/components/molecules/RelatedPosts.test.tsx delete mode 100644 src/components/molecules/RelatedPosts.tsx delete mode 100644 src/components/molecules/Search/SearchButton.module.css delete mode 100644 src/components/molecules/Search/SearchButton.tsx delete mode 100644 src/components/molecules/Search/SearchInput.tsx delete mode 100644 src/components/molecules/Search/SearchResults.tsx delete mode 100644 src/components/molecules/Search/index.module.css delete mode 100644 src/components/molecules/Search/index.tsx delete mode 100644 src/components/molecules/ThemeSwitch.test.tsx delete mode 100644 src/components/molecules/ThemeSwitch.tsx delete mode 100644 src/components/molecules/Vcard.tsx delete mode 100644 src/components/molecules/Web3Donation/InputGroup.test.tsx delete mode 100644 src/components/organisms/Footer.test.tsx delete mode 100644 src/components/organisms/Footer.tsx delete mode 100644 src/components/organisms/Header.test.tsx delete mode 100644 src/components/organisms/Header.tsx delete mode 100644 src/components/templates/Archive.module.css delete mode 100644 src/components/templates/Archive.test.tsx delete mode 100644 src/components/templates/Archive.tsx delete mode 100644 src/components/templates/Page.module.css delete mode 100644 src/components/templates/Page.tsx delete mode 100644 src/components/templates/Photos.module.css delete mode 100644 src/components/templates/Photos.test.tsx delete mode 100644 src/components/templates/Photos.tsx delete mode 100644 src/components/templates/Post/Actions.module.css delete mode 100644 src/components/templates/Post/Actions.tsx delete mode 100644 src/components/templates/Post/Content.module.css delete mode 100644 src/components/templates/Post/Content.tsx delete mode 100644 src/components/templates/Post/Lead.module.css delete mode 100644 src/components/templates/Post/Lead.tsx delete mode 100644 src/components/templates/Post/LinkActions.tsx delete mode 100644 src/components/templates/Post/Meta.tsx delete mode 100644 src/components/templates/Post/More.module.css delete mode 100644 src/components/templates/Post/More.tsx delete mode 100644 src/components/templates/Post/PrevNext.tsx delete mode 100644 src/components/templates/Post/Title.tsx delete mode 100644 src/components/templates/Post/Toc.module.css delete mode 100644 src/components/templates/Post/Toc.tsx delete mode 100644 src/components/templates/Post/index.module.css delete mode 100644 src/components/templates/Post/index.test.tsx delete mode 100644 src/components/templates/Post/index.tsx create mode 100644 src/env.d.ts delete mode 100644 src/helpers/umami.ts delete mode 100644 src/helpers/wrapPageElement.test.tsx delete mode 100644 src/helpers/wrapPageElement.tsx delete mode 100644 src/hooks/useDarkMode.ts delete mode 100644 src/hooks/useSiteMetadata.ts delete mode 100644 src/images/apple-touch-icon.png delete mode 100644 src/images/favicon-16x16.png delete mode 100644 src/images/favicon-32x32.png delete mode 100644 src/images/favicon-96x96.png delete mode 100644 src/images/favicon-mask.svg create mode 100644 src/images/favicon.png create mode 100644 src/images/favicon.svg delete mode 100644 src/images/kremalicious1024.png delete mode 100644 src/images/kremalicious512.png delete mode 100644 src/images/krlcus-cloud16.png delete mode 100644 src/images/krlcus-cloud32.png delete mode 100644 src/images/logo-kremalicious-g-profile.png delete mode 100644 src/images/metro-tile.png delete mode 100644 src/images/touch-icon-192x192.png create mode 100644 src/lib/astro/astro.test.ts create mode 100644 src/lib/astro/getAllPosts.ts create mode 100644 src/lib/astro/getAllPostsForSearch.ts create mode 100644 src/lib/astro/getAllTags.ts create mode 100644 src/lib/astro/getPostsByTag.ts create mode 100644 src/lib/astro/index.ts create mode 100644 src/lib/astro/loadAndFormatCollection.ts create mode 100644 src/lib/astro/sortPosts.ts create mode 100644 src/lib/exif/format.ts create mode 100644 src/lib/exif/index.ts create mode 100644 src/lib/exif/types.d.ts create mode 100644 src/lib/feed.test.ts create mode 100644 src/lib/feed.ts create mode 100644 src/lib/github.test.ts create mode 100644 src/lib/github.ts create mode 100644 src/lib/markdown.ts rename src/{helpers => lib}/rainbowkit.ts (80%) create mode 100644 src/lib/remark-lead-paragraph.test.ts create mode 100644 src/lib/remark-lead-paragraph.ts create mode 100644 src/lib/remark-toc.test.ts create mode 100644 src/lib/remark-toc.ts create mode 100644 src/lib/slugify.test.ts create mode 100644 src/lib/slugify.ts create mode 100644 src/lib/umami.test.ts create mode 100644 src/lib/umami.ts create mode 100644 src/pages/404.astro delete mode 100644 src/pages/404.module.css delete mode 100644 src/pages/404.tsx create mode 100644 src/pages/[...slug].astro delete mode 100644 src/pages/__tests__/404.test.tsx delete mode 100644 src/pages/__tests__/index.test.tsx delete mode 100644 src/pages/__tests__/tags.test.tsx create mode 100644 src/pages/api/posts.ts create mode 100644 src/pages/archive/[page].astro create mode 100644 src/pages/archive/index.astro create mode 100644 src/pages/favicon.ico.ts create mode 100644 src/pages/feed.json.ts create mode 100644 src/pages/feed.xml.ts create mode 100644 src/pages/index.astro delete mode 100644 src/pages/index.module.css delete mode 100644 src/pages/index.tsx create mode 100644 src/pages/manifest.json.ts create mode 100644 src/pages/photos/[page].astro create mode 100644 src/pages/photos/index.astro rename src/pages/{styleguide/index.md => styleguide.md} (99%) delete mode 100644 src/pages/tags.module.css delete mode 100644 src/pages/tags.tsx create mode 100644 src/pages/tags/[tag].astro create mode 100644 src/pages/tags/index.astro create mode 100644 src/pages/thanks.astro delete mode 100644 src/pages/thanks.module.css delete mode 100644 src/pages/thanks.tsx create mode 100644 src/stores/search.ts rename src/{global => styles}/_alerts.css (88%) rename src/{global => styles}/_buttons.css (96%) rename src/{global => styles}/_code.css (51%) rename src/{global => styles}/_variables.css (93%) rename src/{global => styles}/global.css (92%) rename src/{global => styles}/imports.css (100%) delete mode 100644 static/apple-touch-icon.png delete mode 100644 static/favicon.ico create mode 100644 test/__fixtures__/image-with-metadata.jpg create mode 100644 test/__fixtures__/new-article.md create mode 100644 test/__fixtures__/new-photo.md rename {.jest => test}/__mocks__/@rainbow-me/rainbowkit.js (54%) create mode 100644 test/__mocks__/wagmi.ts create mode 100644 test/e2e/404.spec.ts create mode 100644 test/e2e/404.spec.ts-snapshots/matches-screenshot-1-Mobile-Chrome-darwin.png create mode 100644 test/e2e/404.spec.ts-snapshots/matches-screenshot-1-Mobile-Chrome-linux.png create mode 100644 test/e2e/404.spec.ts-snapshots/matches-screenshot-1-Mobile-Safari-darwin.png create mode 100644 test/e2e/404.spec.ts-snapshots/matches-screenshot-1-Mobile-Safari-linux.png create mode 100644 test/e2e/404.spec.ts-snapshots/matches-screenshot-1-chromium-darwin.png create mode 100644 test/e2e/404.spec.ts-snapshots/matches-screenshot-1-chromium-linux.png create mode 100644 test/e2e/404.spec.ts-snapshots/matches-screenshot-1-firefox-darwin.png create mode 100644 test/e2e/404.spec.ts-snapshots/matches-screenshot-1-firefox-linux.png create mode 100644 test/e2e/404.spec.ts-snapshots/matches-screenshot-1-webkit-darwin.png create mode 100644 test/e2e/404.spec.ts-snapshots/matches-screenshot-1-webkit-linux.png create mode 100644 test/e2e/header.spec.ts create mode 100644 test/e2e/header.spec.ts-snapshots/matches-screenshot-1-Mobile-Chrome-darwin.png create mode 100644 test/e2e/header.spec.ts-snapshots/matches-screenshot-1-Mobile-Chrome-linux.png create mode 100644 test/e2e/header.spec.ts-snapshots/matches-screenshot-1-Mobile-Safari-darwin.png create mode 100644 test/e2e/header.spec.ts-snapshots/matches-screenshot-1-Mobile-Safari-linux.png create mode 100644 test/e2e/header.spec.ts-snapshots/matches-screenshot-1-chromium-darwin.png create mode 100644 test/e2e/header.spec.ts-snapshots/matches-screenshot-1-chromium-linux.png create mode 100644 test/e2e/header.spec.ts-snapshots/matches-screenshot-1-firefox-darwin.png create mode 100644 test/e2e/header.spec.ts-snapshots/matches-screenshot-1-firefox-linux.png create mode 100644 test/e2e/header.spec.ts-snapshots/matches-screenshot-1-webkit-darwin.png create mode 100644 test/e2e/header.spec.ts-snapshots/matches-screenshot-1-webkit-linux.png create mode 100644 test/e2e/index.spec.ts create mode 100644 test/e2e/photos.spec.ts create mode 100644 test/e2e/post.spec.ts create mode 100644 test/e2e/thanks.spec.ts create mode 100644 test/playwright.config.ts create mode 100644 test/vitest.config.ts create mode 100644 test/vitest.setup.ts delete mode 100644 vendor/polar-0.0.6.vsix diff --git a/.markdownlint.json b/.config/.markdownlint.json similarity index 100% rename from .markdownlint.json rename to .config/.markdownlint.json diff --git a/.stylelintrc b/.config/.stylelintrc.json similarity index 100% rename from .stylelintrc rename to .config/.stylelintrc.json diff --git a/.config/astro.config.ts b/.config/astro.config.ts new file mode 100644 index 00000000..e0585bdc --- /dev/null +++ b/.config/astro.config.ts @@ -0,0 +1,55 @@ +import { defineConfig } from 'astro/config' +import remarkLeadParagraph from '../src/lib/remark-lead-paragraph' +import remarkToc from '../src/lib/remark-toc' +import react from '@astrojs/react' +import sitemap from '@astrojs/sitemap' +import expressiveCode from 'astro-expressive-code' +import redirects from './redirects.json' +import config from './blog.config' + +// https://astro.build/config +export default defineConfig({ + site: config.siteUrl, + output: 'static', + cacheDir: '.astro', + markdown: { + remarkPlugins: [remarkLeadParagraph, remarkToc as any], + shikiConfig: { + // https://github.com/shikijs/shiki/blob/main/docs/themes.md + theme: 'nord', + langs: [], + wrap: true + } + }, + server: { host: true }, + redirects, + vite: { + resolve: { + // for making content -> src/content symlink work + // https://www.eliostruyf.com/symlink-content-astro-portability/#fix-the-content-issues + preserveSymlinks: true + } + }, + integrations: [ + react(), + expressiveCode({ + theme: 'nord', + // https://github.com/expressive-code/expressive-code/blob/ad08cf74095b30055e841d59497990fade634c86/packages/%40expressive-code/core/src/common/core-styles.ts + styleOverrides: { + borderRadius: 'var(--border-radius)', + borderWidth: 'var(--border-width)', + uiFontFamily: 'var(--font-family-monospace)', + uiFontSize: 'var(--font-size-mini)', + codeFontFamily: 'var(--font-family-monospace)', + codeFontSize: '0.8rem' + } + }), + sitemap({ + filter: (page) => + !page.includes('page/') && + !page.includes('tags/') && + !page.includes('archive/') && + !page.includes('404') + }) + ] +}) diff --git a/.config/aws_redirects.xml b/.config/aws_redirects.xml new file mode 100644 index 00000000..3f3a00f5 --- /dev/null +++ b/.config/aws_redirects.xml @@ -0,0 +1,74 @@ + + + + + lab/ + + + lab.kremalicious.com + + + + + + lab + + + lab.kremalicious.com + + + + + + csspaperstack/ + + + lab.kremalicious.com + + + + + csspaperstack + + + lab.kremalicious.com + + + + + download/ + + + media/ + + + + + feed/ + + + feed.xml + + + + + portfolio/ + + + matthiaskretschmann.com + + + + + + portfolio + + + matthiaskretschmann.com + + + + diff --git a/config.ts b/.config/blog.config.ts similarity index 81% rename from config.ts rename to .config/blog.config.ts index 00a3f578..22d6f5c2 100644 --- a/config.ts +++ b/.config/blog.config.ts @@ -1,15 +1,11 @@ export default { siteTitle: 'kremalicious', - siteTitleShort: 'krlc', siteDescription: 'Blog of designer & developer Matthias Kretschmann', siteUrl: 'https://kremalicious.com', - themeColor: '#e7eef4', - backgroundColor: '#e7eef4', - pathPrefix: null, author: { name: 'Matthias Kretschmann', email: 'm@kretschmann.io', - uri: 'https://matthiaskretschmann.com', + url: 'https://matthiaskretschmann.com', twitter: 'https://twitter.com/kremalicious', mastodon: 'https://mas.to/@krema', github: 'https://github.com/kremalicious', @@ -18,7 +14,7 @@ export default { }, rss: '/feed.xml', jsonfeed: '/feed.json', - itemsPerPage: 24, + itemsPerPage: 30, repoContentPath: 'https://github.com/kremalicious/blog/tree/main/content', menu: [ { @@ -31,7 +27,7 @@ export default { }, { title: 'Goodies', - link: '/archive/goodies' + link: '/tags/goodies' }, { title: 'Tags', diff --git a/.env.sample b/.env.sample index da2f9b42..ea9f4bcb 100644 --- a/.env.sample +++ b/.env.sample @@ -1,7 +1,7 @@ GITHUB_TOKEN=xxx -GATSBY_MAPBOX_ACCESS_TOKEN=xxx -GATSBY_TYPEKIT_ID=xxx -GATSBY_UMAMI_SCRIPT_URL=xxx -GATSBY_UMAMI_WEBSITE_ID=xxx -GATSBY_INFURA_ID=xxx -GATSBY_WALLETCONNECT_ID="xxx" \ No newline at end of file +PUBLIC_MAPBOX_ACCESS_TOKEN=xxx +PUBLIC_TYPEKIT_ID=xxx +PUBLIC_UMAMI_SCRIPT_URL=xxx +PUBLIC_UMAMI_WEBSITE_ID=xxx +PUBLIC_INFURA_ID=xxx +PUBLIC_WALLETCONNECT_ID="xxx" \ No newline at end of file diff --git a/.eslintrc b/.eslintrc.json similarity index 50% rename from .eslintrc rename to .eslintrc.json index 25a091cb..6316e8c9 100644 --- a/.eslintrc +++ b/.eslintrc.json @@ -1,25 +1,23 @@ { "root": true, "env": { + "es6": true, "browser": true, - "node": true, - "es2020": true, - "jest": true + "node": true }, "parser": "@typescript-eslint/parser", "parserOptions": { - "ecmaVersion": 2020, + "ecmaVersion": "latest", "sourceType": "module", "ecmaFeatures": { "jsx": true }, "project": "./tsconfig.json", "tsconfigRootDir": "./" }, - "plugins": ["@typescript-eslint", "react"], + "plugins": ["@typescript-eslint"], "extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended", - "plugin:jsx-a11y/recommended", - "plugin:react/recommended", + "plugin:astro/recommended", "plugin:prettier/recommended" ], "rules": { @@ -29,10 +27,23 @@ "settings": { "react": { "version": "detect" } }, "overrides": [ { - "files": [ - "**/__tests__/**/*.[jt]s?(x)", - "**/?(*.)+(spec|test).[jt]s?(x)" - ], + // Define the configuration for `.astro` file. + "files": ["*.astro"], + // Allows Astro components to be parsed. + "parser": "astro-eslint-parser", + // Parse the script in `.astro` as TypeScript by adding the following configuration. + // It's the setting you need when using TypeScript. + "parserOptions": { + "parser": "@typescript-eslint/parser", + "extraFileExtensions": [".astro"] + }, + "rules": { + // override/add rules settings here, such as: + // "astro/no-set-html-directive": "error" + } + }, + { + "files": ["**/?(*.)+(spec|test).[jt]sx"], "extends": ["plugin:testing-library/react"], "rules": { "testing-library/no-node-access": "off", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b5cd9832..09e8a32f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,88 +8,137 @@ on: branches: - '**' +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PUBLIC_TYPEKIT_ID: ${{ secrets.GATSBY_TYPEKIT_ID }} + PUBLIC_MAPBOX_ACCESS_TOKEN: ${{ secrets.GATSBY_MAPBOX_ACCESS_TOKEN }} + PUBLIC_UMAMI_SCRIPT_URL: ${{ secrets.GATSBY_UMAMI_SCRIPT_URL }} + PUBLIC_UMAMI_WEBSITE_ID: ${{ secrets.GATSBY_UMAMI_WEBSITE_ID }} + PUBLIC_INFURA_ID: ${{ secrets.GATSBY_INFURA_ID }} + PUBLIC_WALLETCONNECT_ID: ${{ secrets.GATSBY_WALLETCONNECT_ID }} + jobs: - test: - runs-on: ubuntu-latest + lint: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-13] + node: ['18'] + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: '18' - - - name: Cache node modules - uses: actions/cache@v3 - with: - path: ~/.npm - key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: ${{ runner.os }}-node- - - - name: Cache Gatsby Cache Folder - uses: actions/cache@v3 - with: - path: .cache - key: ${{ runner.os }}-cache-gatsby - restore-keys: ${{ runner.os }}-cache-gatsby - - - name: Cache Gatsby Public Folder - uses: actions/cache@v3 - with: - path: public/ - key: ${{ runner.os }}-public-gatsby - restore-keys: ${{ runner.os }}-public-gatsby - + node-version: ${{ matrix.node }} + cache: 'npm' - run: npm ci - - run: npm run build - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GATSBY_TYPEKIT_ID: ${{ secrets.GATSBY_TYPEKIT_ID }} - GATSBY_MAPBOX_ACCESS_TOKEN: ${{ secrets.GATSBY_MAPBOX_ACCESS_TOKEN }} - GATSBY_UMAMI_SCRIPT_URL: ${{ secrets.GATSBY_UMAMI_SCRIPT_URL }} - GATSBY_UMAMI_WEBSITE_ID: ${{ secrets.GATSBY_UMAMI_WEBSITE_ID }} - GATSBY_INFURA_ID: ${{ secrets.GATSBY_INFURA_ID }} - - run: npm test - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GATSBY_TYPEKIT_ID: ${{ secrets.GATSBY_TYPEKIT_ID }} - GATSBY_MAPBOX_ACCESS_TOKEN: ${{ secrets.GATSBY_MAPBOX_ACCESS_TOKEN }} - GATSBY_UMAMI_SCRIPT_URL: ${{ secrets.GATSBY_UMAMI_SCRIPT_URL }} - GATSBY_UMAMI_WEBSITE_ID: ${{ secrets.GATSBY_UMAMI_WEBSITE_ID }} - GATSBY_INFURA_ID: ${{ secrets.GATSBY_INFURA_ID }} + - run: npm run lint + typecheck: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-13] + node: ['18'] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + cache: 'npm' + - run: npm ci + - run: npm run prebuild + - run: npm run typecheck + + test-unit: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-13] + node: ['18'] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + cache: 'npm' + - run: npm ci + - run: npm run test:unit - uses: actions/upload-artifact@v3 with: - name: coverage + name: coverage-${{ matrix.os }}-${{ matrix.node }} path: coverage/ + test-e2e: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + node: ['18'] + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + cache: 'npm' + - run: npm ci + - run: npx playwright install --with-deps + - run: npm run test:e2e + + build: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-13] + node: ['18'] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + cache: 'npm' + - name: Cache Astro build output + uses: actions/cache@v3 + with: + path: ${{ github.workspace }}/.astro + key: ${{ matrix.os }}-${{ matrix.node }}-astro-build-${{ hashFiles('content/**/*.jpg', 'content/**/*.png') }} + restore-keys: ${{ matrix.os }}-${{ matrix.node }}-astro-build- + - run: npm ci + - run: npm run build - uses: actions/upload-artifact@v1 if: github.ref == 'refs/heads/main' with: - name: public - path: public + name: dist-${{ matrix.os }}-${{ matrix.node }} + path: dist coverage: runs-on: ubuntu-latest - needs: [test] + needs: [test-unit] if: ${{ success() && github.actor != 'dependabot[bot]' }} steps: - uses: actions/checkout@v3 - uses: actions/download-artifact@v3 with: - name: coverage - - uses: paambaati/codeclimate-action@v2.7.5 + name: coverage-ubuntu-latest-18 + - uses: paambaati/codeclimate-action@v5.0.0 env: CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} deploy: - needs: test + needs: [lint, typecheck, test-unit, test-e2e, build] if: success() && github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/download-artifact@v1 with: - name: public + name: dist-ubuntu-latest-18 - name: Deploy to S3 run: npm run deploy:s3 env: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d1c2fe1c..830c03ed 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -32,7 +32,7 @@ jobs: strategy: fail-fast: false matrix: - language: ['javascript'] + language: ['javascript', 'typescript'] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://git.io/codeql-language-support diff --git a/.gitignore b/.gitignore index 700ef2b8..aec6908e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,26 @@ node_modules .yarnclean -public .cache -plugins/gatsby-redirect-from coverage .env .env.development .nova -src/@types/Gatsby.d.ts \ No newline at end of file + +# build output +dist/ +src/images/components/ + +# generated types +.astro/ + +# autogenerated stuff +public/get/ +src/content/ +src/content +public/post-kbd.css +.config/redirects.json +test-results/ +playwright-report/ +playwright/.cache/ +**/tmp/ +public/theme.js diff --git a/.jest/__fixtures__/avatar.json b/.jest/__fixtures__/avatar.json deleted file mode 100644 index dfd08cc5..00000000 --- a/.jest/__fixtures__/avatar.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "avatar": { - "edges": [ - { - "node": { - "childImageSharp": { - "fixed": { - "aspectRatio": 1, - "width": 80, - "height": 80, - "src": "/static/b61a09d5f4cbd9d8b2844091590ddea4/fce1d/avatar.jpg", - "srcSet": "/static/b61a09d5f4cbd9d8b2844091590ddea4/fce1d/avatar.jpg 1x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/c4de8/avatar.jpg 1.5x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/c3234/avatar.jpg 2x", - "srcWebp": "/static/b61a09d5f4cbd9d8b2844091590ddea4/ad6b8/avatar.webp", - "srcSetWebp": "/static/b61a09d5f4cbd9d8b2844091590ddea4/ad6b8/avatar.webp 1x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/5c322/avatar.webp 1.5x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/5bf6b/avatar.webp 2x", - "originalName": "avatar.jpg" - } - } - } - } - ] - } -} diff --git a/.jest/__fixtures__/github.json b/.jest/__fixtures__/github.json deleted file mode 100644 index b29585d4..00000000 --- a/.jest/__fixtures__/github.json +++ /dev/null @@ -1,219 +0,0 @@ -{ - "github": { - "viewer": { - "repositories": { - "edges": [ - { - "node": { - "name": "csspaperstack", - "url": "https://github.com/kremalicious/csspaperstack", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "hastuzeit", - "url": "https://github.com/kremalicious/hastuzeit", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "Badged", - "url": "https://github.com/kremalicious/Badged", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "hsresponsive", - "url": "https://github.com/kremalicious/hsresponsive", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "dribbble-chromeapp", - "url": "https://github.com/kremalicious/dribbble-chromeapp", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "krtmn", - "url": "https://github.com/kremalicious/krtmn", - "owner": { - "login": "kremalicious" - }, - "object": { - "id": "MDQ6QmxvYjM2MzA0MzQ6NDcwYWRiOTc5MWVjYzZkNmU0YzMzNDQ3ZmZhZjBhNjA0ZGE1NTBkNA==", - "text": "YOURLS Changelog\n================\n\n_This file lists the main changes through all versions of YOURLS. \nFor a much more detailed list, simply refer to [commit messages](https://github.com/YOURLS/YOURLS/commits/master)._\n\n1.7\n---\n- added: support for PDO and MySQLi\n- added: social bookmarklets - share on Twitter, Facebook or Tumblr in a click\n- added: check api.yourls.org if a new version of YOURLS is available\n- added: proxy support - install YOURLS behind a firewall!\n- improved: security regarding SQL injections\n- improved: security regarding your credentials - now auto-encrypted\n- improved: external HTTP request handling\n- improved: ƒυηкƴ UTF-8 titles handling\n- fixed: compatibility with Apache mod_security blocking bookmarklets\n- fixed: lots of bugs\n\n1.6\n---\n- added: مرحبا العالم! Hej verden! 你好世界! Kumusta mundo! Ciao mondo! Hello world! Translation API.\n- added: custom API actions\n- added: support for URLs with common protocols\n- fixed: search and pagination in the admin interface\n- updated: third party libs jQuery, ezSQL, GeoIP\n- improved: sanitizing and escaping functions\n\n1.5.1\n-----\n- added: full jsonp support\n- added: ability to use encrypted passwords in the config file\n- fixed: support for http://www.sho.rt/bleh and http://sho.rt/bleh\n- added: support for any favicon dropped in the /user directory\n- updated: Google Visualization API instead of deprecated Google Charts\n- fixed: bugs, bugs, bugs\n- added: hooks, hooks, hooks\n- improved: things, things, things\n\n1.5\n---\n- added: plugin architecture! OMG plugins!!1!!1!\n- added: directory /user, config.php can be moved there\n- added: new \"instant bookmarklets\"\n- added: 1 click copy-to-clipboard a la bitly\n- change in logic: now all request are handled by PHP and don't rely on .htaccess\n- added: saving URL titles\n- added: support for prefix-n-shorten: sho.rt/http://example.com/\n- added: core plugin to allow hyphens in URLs\n- added: core sample plugin to wrap redirected URLs in a social toolbar\n- added: core sample plugin to show how to create administration page in plugins\n- added: core plugin to display a random pretty background\n- changed: layout now using a more consistent palette, see http://yourls.org/palette\n- added: anti XSS and anti CSRF measures\n- added: interactive map if possible in stat traffic by countries\n- fixed: lots of bugs\n\n1.4.3\n-----\n- fixed bug no-stats-showing-ffs due to inconsistency in DB schema\n- improve error reporting with API method url-stat\n\n1.4.2\n-----\n- fixed: bug in auth function\n- added: sample public API file\n- added: check in API requests for WordPress plugin when adding a new short URL\n- prettier sample public interface\n\n1.4.1\n-----\n- fixed: base 62 URLs (keywords with MiXeD CaSe)\n- new & secure auth method for API calls, with no need to use login & password combo\n- allow SSL enforcement for admin pages\n- new API method: stats for individual URL.\n- prevent internal redirection loops\n- filter and search URLs & short URLs by date\n\n1.4\n---\n- added: an upgrader from 1.3 to 1.4\n- change in logic: now using a global object $ydb for everything related to DB and other globally needed stuff\n- change in logic: include \"load-yourls.php\" instead of \"config.php\" to start engine\n- change in DB schema: now storing URLs with their keyword as used in shorturl, allowing for any keyword length\n- change in DB schema: new table for storing various options including next_id, dropping table of the same name\n- change in DB schema: new table for storing hits (for stats)\n- improved the installer, with .htaccess file creation\n- layout tweak: now prettier, isn't it?\n- stats! OMG stats!\n\n1.3-RC1\n-------\n- added bookmarklet and tools page\n- improved XSS filter when adding new URL\n- code cleanup in admin/index.php to separate code and display\n- added favicon\n- stricter coding to prevent notices with undefined indexes\n- hide PHP notices & SQL errors & warnings, unless YOURLS_DEBUG constant set to true\n\n1.2\n---\n- don't remember. A few tiny stuff for sure.\n\n1.1\n---\n- don't remember. Some little bugs I guess.\n\n1.0.1\n-----\n- don't remember. Trivial stuff probably.\n\n1.0\n---\n- initial release\n" - } - } - }, - { - "node": { - "name": "glassfruit", - "url": "https://github.com/kremalicious/glassfruit", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "kremalicious2", - "url": "https://github.com/kremalicious/kremalicious2", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "wp-icons-template", - "url": "https://github.com/kremalicious/wp-icons-template", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "kbdfun", - "url": "https://github.com/kremalicious/kbdfun", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "dotfiles", - "url": "https://github.com/kremalicious/dotfiles", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "kretschmann.io", - "url": "https://github.com/kremalicious/kretschmann.io", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "blog", - "url": "https://github.com/kremalicious/blog", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "files", - "url": "https://github.com/kremalicious/files", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "appstorebadges", - "url": "https://github.com/kremalicious/appstorebadges", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "hyper-mac-pro", - "url": "https://github.com/kremalicious/hyper-mac-pro", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "ipfs-hosting", - "url": "https://github.com/kremalicious/ipfs-hosting", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "gatsby-plugin-matomo", - "url": "https://github.com/kremalicious/gatsby-plugin-matomo", - "owner": { - "login": "kremalicious" - }, - "object": { - "id": "MDQ6QmxvYjEzMjQ5NDg4NTozNzMwOWUxMTc4MTA5YjJmZDQ3ZDg5YTZlZjIwNjM5NTNlNDNlZjA1", - "text": "### Changelog\n\nAll notable changes to this project will be documented in this file. Dates are displayed in UTC.\n\nGenerated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).\n\n#### [v0.7.2](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.7.1...v0.7.2)\n\n> 13 June 2019\n\n- Fix missing tracking code in rendered HTML [`#18`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/18)\n- update changelog [`57092e5`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/57092e5b0f755867885d4877ba539e2e684eba3c)\n- Release 0.7.2 [`31cabd6`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/31cabd60afbf9da39bce3cbd9187ba203c8f6e93)\n\n#### [v0.7.1](https://github.com/kremalicious/gatsby-plugin-matomo/compare/0.7.0...v0.7.1)\n\n> 10 June 2019\n\n- preconnect to configured Matomo host url [`#17`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/17)\n- Add prettier [`#16`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/16)\n- add prettier [`858fc2e`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/858fc2eb8a58dc49cfe1fea77d2b71c7d2ac4888)\n- new release-it setup [`bbb5f19`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/bbb5f19f94b867b7f7f6959a201690c290ac0fe2)\n- bump packages [`e3479f6`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/e3479f6955f6324140e7243b0f680dd3771250f7)\n\n#### [0.7.0](https://github.com/kremalicious/gatsby-plugin-matomo/compare/0.6.1...0.7.0)\n\n> 30 March 2019\n\n- Page tracking improvements [`#15`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/15)\n- capture and send custom page title [`#11`](https://github.com/kremalicious/gatsby-plugin-matomo/issues/11)\n- better page url & referrer url tracking [`04b8ba1`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/04b8ba19038f49571a0f19099f9af4575739a8fb)\n- update changelog [`24f57da`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/24f57da352ee95781ed2c4268f31adaaa5aa1d82)\n- Release 0.7.0 [`4c36d9c`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/4c36d9c7c6212542fc1b3ebba977ee9c1e9bc526)\n\n#### [0.6.1](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.6.0...0.6.1)\n\n> 30 March 2019\n\n- package updates [`#14`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/14)\n- Update release-it to the latest version 🚀 [`#12`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/12)\n- Update release-it to the latest version 🚀 [`#10`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/10)\n- run changelog before release [`5da11a4`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/5da11a47609f48328d544bab07600576c6f060e0)\n- Release 0.6.1 [`f62c5bf`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/f62c5bf2926726bfc649d24b7fd555974c10482f)\n- chore(package): update release-it to version 10.0.0 [`d56c6c3`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/d56c6c3dba6607f5d67bf70a0953a8d922d84298)\n\n#### [v0.6.0](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.5.1...v0.6.0)\n\n> 5 December 2018\n\n- Path exclusion [`#9`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/9)\n- add changelog [`2b268a1`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/2b268a1c6c0df2b4e344c1f965a665e7be8d9341)\n- allow exclusion of paths [`9464d47`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/9464d47ae1b191ef494148fab4af200e3ea9c85c)\n- make release-it work with conventional-changelog [`2dcd5a7`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/2dcd5a7d02a2c35b95ddbec44d2319b0b25dc682)\n\n#### [v0.5.1](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.5.0...v0.5.1)\n\n> 21 November 2018\n\n- Update release-it to the latest version 🚀 [`#8`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/8)\n- bump packages [`cb26a40`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/cb26a40ece69e756862c5b6986eed60acca61bdd)\n- new Matomo logo [`64dd425`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/64dd4259ecda1fba49ac2bbfba7727bd5a544e3c)\n- Release 0.5.1 [`c442282`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/c44228275734a5edcf790a0bd8c91b9eec634891)\n\n#### [v0.5.0](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.4.1...v0.5.0)\n\n> 6 August 2018\n\n- Add consent mode [`#7`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/7)\n- Scoping js variables to avoid polluting global scope [`#6`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/6)\n- bump packages [`b08b4a5`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/b08b4a5a45c477898b53831e48109bd672e3e11d)\n- add codeclimate config [`a96e8ea`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/a96e8ea5f89fdc07f84bdd49b927c5c757cf4665)\n- Add disableCookies option [`ff9a2c7`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/ff9a2c755867e60964953c109ab382915b662279)\n\n#### [v0.4.1](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.4.0...v0.4.1)\n\n> 28 June 2018\n\n- Update eslint to the latest version 🚀 [`#5`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/5)\n- improvements for SPA tracking [`7d653d5`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/7d653d564cb0ca4ae05d6897d94185ea2198462e)\n- package updates [`347f951`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/347f951174ec6b9f31b91cbd7bce90178eb49a1a)\n- Release 0.4.1 [`b254c13`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/b254c130b9ee8c750e2dd3f69540537094eac235)\n\n#### [v0.4.0](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.3.2...v0.4.0)\n\n> 19 June 2018\n\n- Updates for Gatsby v2 [`#4`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/4)\n- updates for Gatsby v2 [`59e442a`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/59e442a31d85af27f8cdf65a2d15ed8601995fad)\n- package updates [`356e68f`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/356e68faf500baf4c69461fa8323995f30400e24)\n- Release 0.4.0 [`1173236`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/117323688af1963ca5602b13ddd6131aba70376c)\n\n#### [v0.3.2](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.3.1...v0.3.2)\n\n> 23 May 2018\n\n- save some lines [`5034a3b`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/5034a3b8e5201d976f7deb210b471caa50ea16cd)\n- Release 0.3.2 [`c531e47`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/c531e47cf5905acda149a637606ecfea9e2e40bc)\n- change repository field [`260273e`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/260273e0139db6d5bf76bc29c37d2f93fd254f05)\n\n#### [v0.3.1](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.3.0...v0.3.1)\n\n> 14 May 2018\n\n- package updates [`2acbd45`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/2acbd450cb7dffe39c3cb57edbad5aeebe6d7799)\n- Release 0.3.1 [`f9050ce`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/f9050ceaa2b8d214d113ca78785bb7ba78f14d5a)\n- fix environment check [`dc574ab`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/dc574ab72c4ec01c4fa995ae9aa9a1469f04387a)\n\n#### [v0.3.0](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.2.0...v0.3.0)\n\n> 10 May 2018\n\n- allow local piwik.js path to be set [`a15146c`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/a15146c3dc6b692070e09b38646ad925fc92fb28)\n- Release 0.3.0 [`2e36f13`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/2e36f1383d39703d10405b9e82782a6efa54d56f)\n\n#### [v0.2.0](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.1.3...v0.2.0)\n\n> 8 May 2018\n\n- add dev mode [`5c05efe`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/5c05efe1815fb617e0153924696dc6350e2e753c)\n- Release 0.2.0 [`a3ef6d4`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/a3ef6d4c635a15d6cc64c7c3735f551737f3eff7)\n\n#### [v0.1.3](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.1.2...v0.1.3)\n\n> 8 May 2018\n\n- readme updates [`49640f4`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/49640f4d37b54728c5a80ae9f2c63cb103318386)\n- Release 0.1.3 [`0109e19`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/0109e19e106f8620056db2775205101bf4cc1c3b)\n\n#### [v0.1.2](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.1.1...v0.1.2)\n\n> 8 May 2018\n\n- Add Greenkeeper badge 🌴 [`#1`](https://github.com/kremalicious/gatsby-plugin-matomo/pull/1)\n- do nothing on route updates when piwik isn't loaded and in development [`6c0a840`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/6c0a840de21ce46f544b6ce9a7dd63e961e7ab6b)\n- move greenskeeper badge [`b361eef`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/b361eef43bc85c7acf8be73f3067686912ac49b3)\n- Release 0.1.2 [`370025f`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/370025f1ee733d8f87a70def3bf213e52a1125fa)\n\n#### [v0.1.1](https://github.com/kremalicious/gatsby-plugin-matomo/compare/v0.1.0...v0.1.1)\n\n> 7 May 2018\n\n- link up readme badges [`6793592`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/6793592ed28e23177ad0450874ebba055d912dc2)\n- Release 0.1.1 [`48c73ff`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/48c73ff2415dd25ce85924cdd53056b8f561face)\n- docs(readme): add Greenkeeper badge [`ec73329`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/ec73329dd2ad383aa380ed57667da7a7019824a1)\n\n#### v0.1.0\n\n> 7 May 2018\n\n- initial commit 🍹 [`49bffd3`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/49bffd3cf18f1ba9e099048f9a5591f9200f3296)\n- add Travis, add badges, add semi-auto releases [`fe823b7`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/fe823b76a18a5310e3cd19965b9f61e02774f7e0)\n- Release 0.1.0 [`09739a7`](https://github.com/kremalicious/gatsby-plugin-matomo/commit/09739a72c5c2e08b0a74faba8bc4cfb03fdac220)\n" - } - } - }, - { - "node": { - "name": "portfolio", - "url": "https://github.com/kremalicious/portfolio", - "owner": { - "login": "kremalicious" - }, - "object": null - } - }, - { - "node": { - "name": "gatsby-redirect-from", - "url": "https://github.com/kremalicious/gatsby-redirect-from", - "owner": { - "login": "kremalicious" - }, - "object": { - "id": "MDQ6QmxvYjE0NjY2ODk3NDo1YmVmMzg0N2ZlZThjMTk3NThiYThmMjBiMzE3NDFmN2I0YTcwZGU4", - "text": "### Changelog\n\nAll notable changes to this project will be documented in this file. Dates are displayed in UTC.\n\nGenerated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).\n\n#### [v0.2.1](https://github.com/kremalicious/gatsby-redirect-from/compare/v0.2.0...v0.2.1)\n\n> 10 June 2019\n\n- fix auto changelog [`bba9f39`](https://github.com/kremalicious/gatsby-redirect-from/commit/bba9f3915511193384863b61b28b3c7f36d1007f)\n\n#### [v0.2.0](https://github.com/kremalicious/gatsby-redirect-from/compare/v0.1.1...v0.2.0)\n\n> 10 June 2019\n\n- Update docs & dependencies [`#12`](https://github.com/kremalicious/gatsby-redirect-from/pull/12)\n- specify node 8 instead of 10 as engine [`#11`](https://github.com/kremalicious/gatsby-redirect-from/pull/11)\n- Support alternative markdown queries (such as allMdx) [`#10`](https://github.com/kremalicious/gatsby-redirect-from/pull/10)\n- Update release-it to the latest version 🚀 [`#8`](https://github.com/kremalicious/gatsby-redirect-from/pull/8)\n- update docs, mention new options [`07835d8`](https://github.com/kremalicious/gatsby-redirect-from/commit/07835d8405854a4e5a190a6eeeb252604aaaddb7)\n- simplify release-it tasks, add changelog [`3ec4ccf`](https://github.com/kremalicious/gatsby-redirect-from/commit/3ec4ccfb8e19032068fd34c24929179a5237f0ca)\n- add prettier [`3f33f65`](https://github.com/kremalicious/gatsby-redirect-from/commit/3f33f65430126e634f498629e6be8437c6f1ed7b)\n\n#### [v0.1.1](https://github.com/kremalicious/gatsby-redirect-from/compare/v0.1.0...v0.1.1)\n\n> 30 August 2018\n\n- integrate with gatsby-plugin-meta-redirect, notes on server rendering [`2cd07ee`](https://github.com/kremalicious/gatsby-redirect-from/commit/2cd07ee33e2c267b3783630c6e5cfbdb6fb57c4b)\n- Release 0.1.1 [`e72d5ab`](https://github.com/kremalicious/gatsby-redirect-from/commit/e72d5aba5474104d34c99fcc5880a39c02696918)\n\n#### [v0.1.0](https://github.com/kremalicious/gatsby-redirect-from/compare/v0.0.3...v0.1.0)\n\n> 30 August 2018\n\n- babelify build [`#5`](https://github.com/kremalicious/gatsby-redirect-from/pull/5)\n- clarify prerequisites [`139a4af`](https://github.com/kremalicious/gatsby-redirect-from/commit/139a4afc1d81fee444a6bf0c4775c63aea4e7c09)\n- Release 0.1.0 [`9bd28a7`](https://github.com/kremalicious/gatsby-redirect-from/commit/9bd28a7e9cc3cfa83e3b5b7606b08d3cb26fafe0)\n- add npm badge [`53043c8`](https://github.com/kremalicious/gatsby-redirect-from/commit/53043c82f86dfd2e17c1ca0ec4580441baeb6d8d)\n\n#### [v0.0.3](https://github.com/kremalicious/gatsby-redirect-from/compare/v0.0.2...v0.0.3)\n\n> 29 August 2018\n\n- fix publish [`c91a362`](https://github.com/kremalicious/gatsby-redirect-from/commit/c91a3626390bfa632322007300818e58a25d75d0)\n- Release 0.0.3 [`f1d4982`](https://github.com/kremalicious/gatsby-redirect-from/commit/f1d4982d2424beb67119702a8181d4284ffe399e)\n\n#### v0.0.2\n\n> 29 August 2018\n\n- Add Greenkeeper badge 🌴 [`#1`](https://github.com/kremalicious/gatsby-redirect-from/pull/1)\n- initial commit 🍷 [`dfb3bb0`](https://github.com/kremalicious/gatsby-redirect-from/commit/dfb3bb0954b1933c4d9e36ebc8cb302a0dc70795)\n- Release 0.0.2 [`6924e7b`](https://github.com/kremalicious/gatsby-redirect-from/commit/6924e7b2d9d00a6eb6a03eeb328f29d561dbf904)\n- fix test [`b0129a5`](https://github.com/kremalicious/gatsby-redirect-from/commit/b0129a5ee73d292422a2f7746412aa55a0ce1097)\n" - } - } - } - ] - } - } - } -} diff --git a/.jest/__fixtures__/home.json b/.jest/__fixtures__/home.json deleted file mode 100644 index 46be0217..00000000 --- a/.jest/__fixtures__/home.json +++ /dev/null @@ -1,523 +0,0 @@ -{ - "latestArticles": { - "edges": [ - { - "node": { - "id": "108cdbf6-2442-54b5-887c-aad821fba6c2", - "fileAbsolutePath": "/Users/m/Code/blog/content/articles/2020-05-22-gatsby-redirect-from/index.md", - "frontmatter": { - "title": "Redirect plugin for Markdown Pages in Gatsby", - "linkurl": null, - "updated": "2020-05-23T09:35:12.000Z", - "image": { - "childImageSharp": { - "original": { - "src": "/static/gatsby-redirect-from-teaser-0d31de44f593361b78d2af6a9c030de3.png" - }, - "fluid": { - "aspectRatio": 3, - "src": "/static/0d31de44f593361b78d2af6a9c030de3/7547c/gatsby-redirect-from-teaser.png", - "srcSet": "/static/0d31de44f593361b78d2af6a9c030de3/f353c/gatsby-redirect-from-teaser.png 105w,\n/static/0d31de44f593361b78d2af6a9c030de3/45430/gatsby-redirect-from-teaser.png 210w,\n/static/0d31de44f593361b78d2af6a9c030de3/7547c/gatsby-redirect-from-teaser.png 420w,\n/static/0d31de44f593361b78d2af6a9c030de3/4f753/gatsby-redirect-from-teaser.png 630w,\n/static/0d31de44f593361b78d2af6a9c030de3/60369/gatsby-redirect-from-teaser.png 840w,\n/static/0d31de44f593361b78d2af6a9c030de3/6364d/gatsby-redirect-from-teaser.png 1880w", - "srcWebp": "/static/0d31de44f593361b78d2af6a9c030de3/8a0fd/gatsby-redirect-from-teaser.webp", - "srcSetWebp": "/static/0d31de44f593361b78d2af6a9c030de3/2aec1/gatsby-redirect-from-teaser.webp 105w,\n/static/0d31de44f593361b78d2af6a9c030de3/74e55/gatsby-redirect-from-teaser.webp 210w,\n/static/0d31de44f593361b78d2af6a9c030de3/8a0fd/gatsby-redirect-from-teaser.webp 420w,\n/static/0d31de44f593361b78d2af6a9c030de3/70212/gatsby-redirect-from-teaser.webp 630w,\n/static/0d31de44f593361b78d2af6a9c030de3/a9b7e/gatsby-redirect-from-teaser.webp 840w,\n/static/0d31de44f593361b78d2af6a9c030de3/b6972/gatsby-redirect-from-teaser.webp 1880w", - "sizes": "(max-width: 420px) 100vw, 420px" - } - } - }, - "tags": ["goodies", "gatsby", "development"] - }, - "fields": { - "slug": "/gatsby-redirect-from", - "date": "2020-05-22T14:08:00.367Z", - "type": "article" - } - } - }, - { - "node": { - "id": "cf701f60-bbb5-544f-bb13-97aa884b7ad7", - "fileAbsolutePath": "/Users/m/Code/blog/content/articles/2020-05-08-uses/index.md", - "frontmatter": { - "title": "/uses", - "linkurl": null, - "updated": "2020-07-30T13:58:12.000Z", - "image": { - "childImageSharp": { - "original": { - "src": "/static/uses-teaser-dfb23ab7203b0f61b838c98f23ea7852.png" - }, - "fluid": { - "aspectRatio": 3, - "src": "/static/dfb23ab7203b0f61b838c98f23ea7852/7547c/uses-teaser.png", - "srcSet": "/static/dfb23ab7203b0f61b838c98f23ea7852/f353c/uses-teaser.png 105w,\n/static/dfb23ab7203b0f61b838c98f23ea7852/45430/uses-teaser.png 210w,\n/static/dfb23ab7203b0f61b838c98f23ea7852/7547c/uses-teaser.png 420w,\n/static/dfb23ab7203b0f61b838c98f23ea7852/4f753/uses-teaser.png 630w,\n/static/dfb23ab7203b0f61b838c98f23ea7852/60369/uses-teaser.png 840w,\n/static/dfb23ab7203b0f61b838c98f23ea7852/6364d/uses-teaser.png 1880w", - "srcWebp": "/static/dfb23ab7203b0f61b838c98f23ea7852/8a0fd/uses-teaser.webp", - "srcSetWebp": "/static/dfb23ab7203b0f61b838c98f23ea7852/2aec1/uses-teaser.webp 105w,\n/static/dfb23ab7203b0f61b838c98f23ea7852/74e55/uses-teaser.webp 210w,\n/static/dfb23ab7203b0f61b838c98f23ea7852/8a0fd/uses-teaser.webp 420w,\n/static/dfb23ab7203b0f61b838c98f23ea7852/70212/uses-teaser.webp 630w,\n/static/dfb23ab7203b0f61b838c98f23ea7852/a9b7e/uses-teaser.webp 840w,\n/static/dfb23ab7203b0f61b838c98f23ea7852/b6972/uses-teaser.webp 1880w", - "sizes": "(max-width: 420px) 100vw, 420px" - } - } - }, - "tags": [ - "personal", - "macos", - "ios", - "mac", - "iphone", - "design", - "development" - ] - }, - "fields": { - "slug": "/uses", - "date": "2020-05-10T21:51:12.000Z", - "type": "article" - } - } - }, - { - "node": { - "id": "d7662b67-4a20-52af-a847-9c4debcf1cec", - "fileAbsolutePath": "/Users/m/Code/blog/content/articles/2020-03-04-raspberry-pi-file-and-screen-sharing-macos-ios/index.md", - "frontmatter": { - "title": "Setup Raspberry Pi File and Screen Sharing for macOS & iOS", - "linkurl": null, - "updated": null, - "image": { - "childImageSharp": { - "original": { - "src": "/static/raspberry-pi-file-and-screen-sharing-macos-ios-teaser-a5f639b239acd8c475ff7dd3844508e8.png" - }, - "fluid": { - "aspectRatio": 3, - "src": "/static/a5f639b239acd8c475ff7dd3844508e8/7547c/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.png", - "srcSet": "/static/a5f639b239acd8c475ff7dd3844508e8/f353c/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.png 105w,\n/static/a5f639b239acd8c475ff7dd3844508e8/45430/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.png 210w,\n/static/a5f639b239acd8c475ff7dd3844508e8/7547c/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.png 420w,\n/static/a5f639b239acd8c475ff7dd3844508e8/4f753/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.png 630w,\n/static/a5f639b239acd8c475ff7dd3844508e8/60369/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.png 840w,\n/static/a5f639b239acd8c475ff7dd3844508e8/6364d/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.png 1880w", - "srcWebp": "/static/a5f639b239acd8c475ff7dd3844508e8/8a0fd/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.webp", - "srcSetWebp": "/static/a5f639b239acd8c475ff7dd3844508e8/2aec1/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.webp 105w,\n/static/a5f639b239acd8c475ff7dd3844508e8/74e55/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.webp 210w,\n/static/a5f639b239acd8c475ff7dd3844508e8/8a0fd/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.webp 420w,\n/static/a5f639b239acd8c475ff7dd3844508e8/70212/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.webp 630w,\n/static/a5f639b239acd8c475ff7dd3844508e8/a9b7e/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.webp 840w,\n/static/a5f639b239acd8c475ff7dd3844508e8/b6972/raspberry-pi-file-and-screen-sharing-macos-ios-teaser.webp 1880w", - "sizes": "(max-width: 420px) 100vw, 420px" - } - } - }, - "tags": [ - "macos", - "ios", - "linux", - "raspberrypi", - "ubuntu", - "tutorial", - "avahi" - ] - }, - "fields": { - "slug": "/raspberry-pi-file-and-screen-sharing-macos-ios", - "date": "2020-03-04T18:35:26.815Z", - "type": "article" - } - } - }, - { - "node": { - "id": "9acfbf40-a90a-56c3-ab08-b98be93bcd9a", - "fileAbsolutePath": "/Users/m/Code/blog/content/articles/2019-10-24-ocean-protocol-and-ipfs-sitting-in-the-merkle-tree/index.md", - "frontmatter": { - "title": "Ocean Protocol and IPFS, Sitting In The Merkle Tree", - "linkurl": null, - "updated": null, - "image": { - "childImageSharp": { - "original": { - "src": "/static/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser-f724bdaae38e81ec90b01ec6b8412cc8.png" - }, - "fluid": { - "aspectRatio": 3, - "src": "/static/f724bdaae38e81ec90b01ec6b8412cc8/7547c/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.png", - "srcSet": "/static/f724bdaae38e81ec90b01ec6b8412cc8/f353c/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.png 105w,\n/static/f724bdaae38e81ec90b01ec6b8412cc8/45430/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.png 210w,\n/static/f724bdaae38e81ec90b01ec6b8412cc8/7547c/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.png 420w,\n/static/f724bdaae38e81ec90b01ec6b8412cc8/4f753/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.png 630w,\n/static/f724bdaae38e81ec90b01ec6b8412cc8/60369/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.png 840w,\n/static/f724bdaae38e81ec90b01ec6b8412cc8/766ad/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.png 2000w", - "srcWebp": "/static/f724bdaae38e81ec90b01ec6b8412cc8/8a0fd/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.webp", - "srcSetWebp": "/static/f724bdaae38e81ec90b01ec6b8412cc8/2aec1/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.webp 105w,\n/static/f724bdaae38e81ec90b01ec6b8412cc8/74e55/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.webp 210w,\n/static/f724bdaae38e81ec90b01ec6b8412cc8/8a0fd/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.webp 420w,\n/static/f724bdaae38e81ec90b01ec6b8412cc8/70212/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.webp 630w,\n/static/f724bdaae38e81ec90b01ec6b8412cc8/a9b7e/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.webp 840w,\n/static/f724bdaae38e81ec90b01ec6b8412cc8/52dbc/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree-teaser.webp 2000w", - "sizes": "(max-width: 420px) 100vw, 420px" - } - } - }, - "tags": [ - "oceanprotocol", - "blockchain", - "design", - "development", - "ipfs", - "web3" - ] - }, - "fields": { - "slug": "/ocean-protocol-and-ipfs-sitting-in-the-merkle-tree", - "date": "2019-10-24T00:00:00.000Z", - "type": "article" - } - } - }, - { - "node": { - "id": "45d2cb0a-5f77-5726-86d7-72b38b6c8024", - "fileAbsolutePath": "/Users/m/Code/blog/content/articles/2019-07-18-the-commons-marketplace-in-pacific-network/index.md", - "frontmatter": { - "title": "The Commons Marketplace in Pacific Network", - "linkurl": null, - "updated": null, - "image": { - "childImageSharp": { - "original": { - "src": "/static/the-commons-marketplace-in-pacific-network-teaser-2db57438c9f98018d8b61d9224d3fb77.png" - }, - "fluid": { - "aspectRatio": 3, - "src": "/static/2db57438c9f98018d8b61d9224d3fb77/7547c/the-commons-marketplace-in-pacific-network-teaser.png", - "srcSet": "/static/2db57438c9f98018d8b61d9224d3fb77/f353c/the-commons-marketplace-in-pacific-network-teaser.png 105w,\n/static/2db57438c9f98018d8b61d9224d3fb77/45430/the-commons-marketplace-in-pacific-network-teaser.png 210w,\n/static/2db57438c9f98018d8b61d9224d3fb77/7547c/the-commons-marketplace-in-pacific-network-teaser.png 420w,\n/static/2db57438c9f98018d8b61d9224d3fb77/4f753/the-commons-marketplace-in-pacific-network-teaser.png 630w,\n/static/2db57438c9f98018d8b61d9224d3fb77/60369/the-commons-marketplace-in-pacific-network-teaser.png 840w,\n/static/2db57438c9f98018d8b61d9224d3fb77/fe119/the-commons-marketplace-in-pacific-network-teaser.png 2762w", - "srcWebp": "/static/2db57438c9f98018d8b61d9224d3fb77/8a0fd/the-commons-marketplace-in-pacific-network-teaser.webp", - "srcSetWebp": "/static/2db57438c9f98018d8b61d9224d3fb77/2aec1/the-commons-marketplace-in-pacific-network-teaser.webp 105w,\n/static/2db57438c9f98018d8b61d9224d3fb77/74e55/the-commons-marketplace-in-pacific-network-teaser.webp 210w,\n/static/2db57438c9f98018d8b61d9224d3fb77/8a0fd/the-commons-marketplace-in-pacific-network-teaser.webp 420w,\n/static/2db57438c9f98018d8b61d9224d3fb77/70212/the-commons-marketplace-in-pacific-network-teaser.webp 630w,\n/static/2db57438c9f98018d8b61d9224d3fb77/a9b7e/the-commons-marketplace-in-pacific-network-teaser.webp 840w,\n/static/2db57438c9f98018d8b61d9224d3fb77/dc0ca/the-commons-marketplace-in-pacific-network-teaser.webp 2762w", - "sizes": "(max-width: 420px) 100vw, 420px" - } - } - }, - "tags": [ - "oceanprotocol", - "blockchain", - "design", - "development", - "web3" - ] - }, - "fields": { - "slug": "/the-commons-marketplace-in-pacific-network", - "date": "2019-07-18T00:00:00.000Z", - "type": "article" - } - } - } - ] - }, - "latestPhotos": { - "edges": [ - { - "node": { - "id": "5f4558ee-381e-5fb0-9c0e-b60115b6e22e", - "frontmatter": { - "title": "The Light That Never Goes Out", - "image": { - "childImageSharp": { - "original": { - "src": "/static/2020-02-14-the-light-that-never-goes-out-a389a64d6f51e45fa8e0a7ea98f85fa4.jpg" - }, - "fluid": { - "aspectRatio": 1, - "src": "/static/a389a64d6f51e45fa8e0a7ea98f85fa4/0f41b/2020-02-14-the-light-that-never-goes-out.jpg", - "srcSet": "/static/a389a64d6f51e45fa8e0a7ea98f85fa4/73124/2020-02-14-the-light-that-never-goes-out.jpg 75w,\n/static/a389a64d6f51e45fa8e0a7ea98f85fa4/712e7/2020-02-14-the-light-that-never-goes-out.jpg 150w,\n/static/a389a64d6f51e45fa8e0a7ea98f85fa4/0f41b/2020-02-14-the-light-that-never-goes-out.jpg 300w,\n/static/a389a64d6f51e45fa8e0a7ea98f85fa4/270e8/2020-02-14-the-light-that-never-goes-out.jpg 450w,\n/static/a389a64d6f51e45fa8e0a7ea98f85fa4/aa95b/2020-02-14-the-light-that-never-goes-out.jpg 600w,\n/static/a389a64d6f51e45fa8e0a7ea98f85fa4/37b83/2020-02-14-the-light-that-never-goes-out.jpg 2772w", - "srcWebp": "/static/a389a64d6f51e45fa8e0a7ea98f85fa4/40e2f/2020-02-14-the-light-that-never-goes-out.webp", - "srcSetWebp": "/static/a389a64d6f51e45fa8e0a7ea98f85fa4/37dc9/2020-02-14-the-light-that-never-goes-out.webp 75w,\n/static/a389a64d6f51e45fa8e0a7ea98f85fa4/37a2a/2020-02-14-the-light-that-never-goes-out.webp 150w,\n/static/a389a64d6f51e45fa8e0a7ea98f85fa4/40e2f/2020-02-14-the-light-that-never-goes-out.webp 300w,\n/static/a389a64d6f51e45fa8e0a7ea98f85fa4/6a707/2020-02-14-the-light-that-never-goes-out.webp 450w,\n/static/a389a64d6f51e45fa8e0a7ea98f85fa4/bf714/2020-02-14-the-light-that-never-goes-out.webp 600w,\n/static/a389a64d6f51e45fa8e0a7ea98f85fa4/0a795/2020-02-14-the-light-that-never-goes-out.webp 2772w", - "sizes": "(max-width: 300px) 100vw, 300px" - } - } - } - }, - "fields": { - "slug": "/the-light-that-never-goes-out", - "type": "photo" - } - } - }, - { - "node": { - "id": "8c2d7d7e-3799-5f1e-8499-922d58a636ee", - "frontmatter": { - "title": "Balloon Dog", - "image": { - "childImageSharp": { - "original": { - "src": "/static/2020-01-17-balloon-dog-28916b152705a4f518c85519b6c1822b.jpg" - }, - "fluid": { - "aspectRatio": 1, - "src": "/static/28916b152705a4f518c85519b6c1822b/0f41b/2020-01-17-balloon-dog.jpg", - "srcSet": "/static/28916b152705a4f518c85519b6c1822b/73124/2020-01-17-balloon-dog.jpg 75w,\n/static/28916b152705a4f518c85519b6c1822b/712e7/2020-01-17-balloon-dog.jpg 150w,\n/static/28916b152705a4f518c85519b6c1822b/0f41b/2020-01-17-balloon-dog.jpg 300w,\n/static/28916b152705a4f518c85519b6c1822b/270e8/2020-01-17-balloon-dog.jpg 450w,\n/static/28916b152705a4f518c85519b6c1822b/aa95b/2020-01-17-balloon-dog.jpg 600w,\n/static/28916b152705a4f518c85519b6c1822b/d5887/2020-01-17-balloon-dog.jpg 2792w", - "srcWebp": "/static/28916b152705a4f518c85519b6c1822b/40e2f/2020-01-17-balloon-dog.webp", - "srcSetWebp": "/static/28916b152705a4f518c85519b6c1822b/37dc9/2020-01-17-balloon-dog.webp 75w,\n/static/28916b152705a4f518c85519b6c1822b/37a2a/2020-01-17-balloon-dog.webp 150w,\n/static/28916b152705a4f518c85519b6c1822b/40e2f/2020-01-17-balloon-dog.webp 300w,\n/static/28916b152705a4f518c85519b6c1822b/6a707/2020-01-17-balloon-dog.webp 450w,\n/static/28916b152705a4f518c85519b6c1822b/bf714/2020-01-17-balloon-dog.webp 600w,\n/static/28916b152705a4f518c85519b6c1822b/57701/2020-01-17-balloon-dog.webp 2792w", - "sizes": "(max-width: 300px) 100vw, 300px" - } - } - } - }, - "fields": { - "slug": "/balloon-dog", - "type": "photo" - } - } - }, - { - "node": { - "id": "a1cd842c-4755-508e-9709-2daabeb783a4", - "frontmatter": { - "title": "Bremen Cathedral", - "image": { - "childImageSharp": { - "original": { - "src": "/static/2020-01-17-bremen-cathedral-7203580f941ea9a9b0a27d6f41686724.jpg" - }, - "fluid": { - "aspectRatio": 1, - "src": "/static/7203580f941ea9a9b0a27d6f41686724/0f41b/2020-01-17-bremen-cathedral.jpg", - "srcSet": "/static/7203580f941ea9a9b0a27d6f41686724/73124/2020-01-17-bremen-cathedral.jpg 75w,\n/static/7203580f941ea9a9b0a27d6f41686724/712e7/2020-01-17-bremen-cathedral.jpg 150w,\n/static/7203580f941ea9a9b0a27d6f41686724/0f41b/2020-01-17-bremen-cathedral.jpg 300w,\n/static/7203580f941ea9a9b0a27d6f41686724/270e8/2020-01-17-bremen-cathedral.jpg 450w,\n/static/7203580f941ea9a9b0a27d6f41686724/aa95b/2020-01-17-bremen-cathedral.jpg 600w,\n/static/7203580f941ea9a9b0a27d6f41686724/ffda5/2020-01-17-bremen-cathedral.jpg 3115w", - "srcWebp": "/static/7203580f941ea9a9b0a27d6f41686724/40e2f/2020-01-17-bremen-cathedral.webp", - "srcSetWebp": "/static/7203580f941ea9a9b0a27d6f41686724/37dc9/2020-01-17-bremen-cathedral.webp 75w,\n/static/7203580f941ea9a9b0a27d6f41686724/37a2a/2020-01-17-bremen-cathedral.webp 150w,\n/static/7203580f941ea9a9b0a27d6f41686724/40e2f/2020-01-17-bremen-cathedral.webp 300w,\n/static/7203580f941ea9a9b0a27d6f41686724/6a707/2020-01-17-bremen-cathedral.webp 450w,\n/static/7203580f941ea9a9b0a27d6f41686724/bf714/2020-01-17-bremen-cathedral.webp 600w,\n/static/7203580f941ea9a9b0a27d6f41686724/ba27b/2020-01-17-bremen-cathedral.webp 3115w", - "sizes": "(max-width: 300px) 100vw, 300px" - } - } - } - }, - "fields": { - "slug": "/bremen-cathedral", - "type": "photo" - } - } - }, - { - "node": { - "id": "82a3ca09-ff38-5c2a-8b4f-6f5150d9448e", - "frontmatter": { - "title": "RAW Gelände", - "image": { - "childImageSharp": { - "original": { - "src": "/static/2020-01-05-raw-gelande-6d40de77304f8a335d88447d16125e5a.jpg" - }, - "fluid": { - "aspectRatio": 1, - "src": "/static/6d40de77304f8a335d88447d16125e5a/0f41b/2020-01-05-raw-gelande.jpg", - "srcSet": "/static/6d40de77304f8a335d88447d16125e5a/73124/2020-01-05-raw-gelande.jpg 75w,\n/static/6d40de77304f8a335d88447d16125e5a/712e7/2020-01-05-raw-gelande.jpg 150w,\n/static/6d40de77304f8a335d88447d16125e5a/0f41b/2020-01-05-raw-gelande.jpg 300w,\n/static/6d40de77304f8a335d88447d16125e5a/270e8/2020-01-05-raw-gelande.jpg 450w,\n/static/6d40de77304f8a335d88447d16125e5a/aa95b/2020-01-05-raw-gelande.jpg 600w,\n/static/6d40de77304f8a335d88447d16125e5a/30037/2020-01-05-raw-gelande.jpg 3024w", - "srcWebp": "/static/6d40de77304f8a335d88447d16125e5a/40e2f/2020-01-05-raw-gelande.webp", - "srcSetWebp": "/static/6d40de77304f8a335d88447d16125e5a/37dc9/2020-01-05-raw-gelande.webp 75w,\n/static/6d40de77304f8a335d88447d16125e5a/37a2a/2020-01-05-raw-gelande.webp 150w,\n/static/6d40de77304f8a335d88447d16125e5a/40e2f/2020-01-05-raw-gelande.webp 300w,\n/static/6d40de77304f8a335d88447d16125e5a/6a707/2020-01-05-raw-gelande.webp 450w,\n/static/6d40de77304f8a335d88447d16125e5a/bf714/2020-01-05-raw-gelande.webp 600w,\n/static/6d40de77304f8a335d88447d16125e5a/859d2/2020-01-05-raw-gelande.webp 3024w", - "sizes": "(max-width: 300px) 100vw, 300px" - } - } - } - }, - "fields": { - "slug": "/raw-gelande", - "type": "photo" - } - } - }, - { - "node": { - "id": "7c499977-3837-54bd-a8e9-945fb0e5c04a", - "frontmatter": { - "title": "Helmut Newton Foundation", - "image": { - "childImageSharp": { - "original": { - "src": "/static/2019-11-16-helmut-newton-foundation-d5cf288572434a487b055397b4cec51b.jpg" - }, - "fluid": { - "aspectRatio": 1, - "src": "/static/d5cf288572434a487b055397b4cec51b/0f41b/2019-11-16-helmut-newton-foundation.jpg", - "srcSet": "/static/d5cf288572434a487b055397b4cec51b/73124/2019-11-16-helmut-newton-foundation.jpg 75w,\n/static/d5cf288572434a487b055397b4cec51b/712e7/2019-11-16-helmut-newton-foundation.jpg 150w,\n/static/d5cf288572434a487b055397b4cec51b/0f41b/2019-11-16-helmut-newton-foundation.jpg 300w,\n/static/d5cf288572434a487b055397b4cec51b/270e8/2019-11-16-helmut-newton-foundation.jpg 450w,\n/static/d5cf288572434a487b055397b4cec51b/aa95b/2019-11-16-helmut-newton-foundation.jpg 600w,\n/static/d5cf288572434a487b055397b4cec51b/d3f44/2019-11-16-helmut-newton-foundation.jpg 3620w", - "srcWebp": "/static/d5cf288572434a487b055397b4cec51b/40e2f/2019-11-16-helmut-newton-foundation.webp", - "srcSetWebp": "/static/d5cf288572434a487b055397b4cec51b/37dc9/2019-11-16-helmut-newton-foundation.webp 75w,\n/static/d5cf288572434a487b055397b4cec51b/37a2a/2019-11-16-helmut-newton-foundation.webp 150w,\n/static/d5cf288572434a487b055397b4cec51b/40e2f/2019-11-16-helmut-newton-foundation.webp 300w,\n/static/d5cf288572434a487b055397b4cec51b/6a707/2019-11-16-helmut-newton-foundation.webp 450w,\n/static/d5cf288572434a487b055397b4cec51b/bf714/2019-11-16-helmut-newton-foundation.webp 600w,\n/static/d5cf288572434a487b055397b4cec51b/40f07/2019-11-16-helmut-newton-foundation.webp 3620w", - "sizes": "(max-width: 300px) 100vw, 300px" - } - } - } - }, - "fields": { - "slug": "/helmut-newton-foundation", - "type": "photo" - } - } - }, - { - "node": { - "id": "bbf028a7-0973-5d1e-8099-d6409936e73e", - "frontmatter": { - "title": "Országház III", - "image": { - "childImageSharp": { - "original": { - "src": "/static/2019-11-03-orszaghaz-iii-7c4460abda635fd1de2856343196a260.jpg" - }, - "fluid": { - "aspectRatio": 1, - "src": "/static/7c4460abda635fd1de2856343196a260/0f41b/2019-11-03-orszaghaz-iii.jpg", - "srcSet": "/static/7c4460abda635fd1de2856343196a260/73124/2019-11-03-orszaghaz-iii.jpg 75w,\n/static/7c4460abda635fd1de2856343196a260/712e7/2019-11-03-orszaghaz-iii.jpg 150w,\n/static/7c4460abda635fd1de2856343196a260/0f41b/2019-11-03-orszaghaz-iii.jpg 300w,\n/static/7c4460abda635fd1de2856343196a260/270e8/2019-11-03-orszaghaz-iii.jpg 450w,\n/static/7c4460abda635fd1de2856343196a260/aa95b/2019-11-03-orszaghaz-iii.jpg 600w,\n/static/7c4460abda635fd1de2856343196a260/9ce23/2019-11-03-orszaghaz-iii.jpg 3813w", - "srcWebp": "/static/7c4460abda635fd1de2856343196a260/40e2f/2019-11-03-orszaghaz-iii.webp", - "srcSetWebp": "/static/7c4460abda635fd1de2856343196a260/37dc9/2019-11-03-orszaghaz-iii.webp 75w,\n/static/7c4460abda635fd1de2856343196a260/37a2a/2019-11-03-orszaghaz-iii.webp 150w,\n/static/7c4460abda635fd1de2856343196a260/40e2f/2019-11-03-orszaghaz-iii.webp 300w,\n/static/7c4460abda635fd1de2856343196a260/6a707/2019-11-03-orszaghaz-iii.webp 450w,\n/static/7c4460abda635fd1de2856343196a260/bf714/2019-11-03-orszaghaz-iii.webp 600w,\n/static/7c4460abda635fd1de2856343196a260/e9670/2019-11-03-orszaghaz-iii.webp 3813w", - "sizes": "(max-width: 300px) 100vw, 300px" - } - } - } - }, - "fields": { - "slug": "/orszaghaz-iii", - "type": "photo" - } - } - }, - { - "node": { - "id": "6effe45d-0884-527c-9fba-6f7f567979fd", - "frontmatter": { - "title": "Országház II", - "image": { - "childImageSharp": { - "original": { - "src": "/static/2019-11-03-orszaghaz-ii-2dbcf257b4bdf625c24fede935d32425.jpg" - }, - "fluid": { - "aspectRatio": 1, - "src": "/static/2dbcf257b4bdf625c24fede935d32425/0f41b/2019-11-03-orszaghaz-ii.jpg", - "srcSet": "/static/2dbcf257b4bdf625c24fede935d32425/73124/2019-11-03-orszaghaz-ii.jpg 75w,\n/static/2dbcf257b4bdf625c24fede935d32425/712e7/2019-11-03-orszaghaz-ii.jpg 150w,\n/static/2dbcf257b4bdf625c24fede935d32425/0f41b/2019-11-03-orszaghaz-ii.jpg 300w,\n/static/2dbcf257b4bdf625c24fede935d32425/270e8/2019-11-03-orszaghaz-ii.jpg 450w,\n/static/2dbcf257b4bdf625c24fede935d32425/aa95b/2019-11-03-orszaghaz-ii.jpg 600w,\n/static/2dbcf257b4bdf625c24fede935d32425/d1a04/2019-11-03-orszaghaz-ii.jpg 3793w", - "srcWebp": "/static/2dbcf257b4bdf625c24fede935d32425/40e2f/2019-11-03-orszaghaz-ii.webp", - "srcSetWebp": "/static/2dbcf257b4bdf625c24fede935d32425/37dc9/2019-11-03-orszaghaz-ii.webp 75w,\n/static/2dbcf257b4bdf625c24fede935d32425/37a2a/2019-11-03-orszaghaz-ii.webp 150w,\n/static/2dbcf257b4bdf625c24fede935d32425/40e2f/2019-11-03-orszaghaz-ii.webp 300w,\n/static/2dbcf257b4bdf625c24fede935d32425/6a707/2019-11-03-orszaghaz-ii.webp 450w,\n/static/2dbcf257b4bdf625c24fede935d32425/bf714/2019-11-03-orszaghaz-ii.webp 600w,\n/static/2dbcf257b4bdf625c24fede935d32425/90141/2019-11-03-orszaghaz-ii.webp 3793w", - "sizes": "(max-width: 300px) 100vw, 300px" - } - } - } - }, - "fields": { - "slug": "/orszaghaz-ii", - "type": "photo" - } - } - }, - { - "node": { - "id": "c80697e5-681d-5fcc-9dab-c3a3821ff0b1", - "frontmatter": { - "title": "Országház I", - "image": { - "childImageSharp": { - "original": { - "src": "/static/2019-11-02-orszaghaz-i-36d87329aeeda296ae923606e5a4a785.jpg" - }, - "fluid": { - "aspectRatio": 1, - "src": "/static/36d87329aeeda296ae923606e5a4a785/0f41b/2019-11-02-orszaghaz-i.jpg", - "srcSet": "/static/36d87329aeeda296ae923606e5a4a785/73124/2019-11-02-orszaghaz-i.jpg 75w,\n/static/36d87329aeeda296ae923606e5a4a785/712e7/2019-11-02-orszaghaz-i.jpg 150w,\n/static/36d87329aeeda296ae923606e5a4a785/0f41b/2019-11-02-orszaghaz-i.jpg 300w,\n/static/36d87329aeeda296ae923606e5a4a785/270e8/2019-11-02-orszaghaz-i.jpg 450w,\n/static/36d87329aeeda296ae923606e5a4a785/aa95b/2019-11-02-orszaghaz-i.jpg 600w,\n/static/36d87329aeeda296ae923606e5a4a785/506d6/2019-11-02-orszaghaz-i.jpg 3708w", - "srcWebp": "/static/36d87329aeeda296ae923606e5a4a785/40e2f/2019-11-02-orszaghaz-i.webp", - "srcSetWebp": "/static/36d87329aeeda296ae923606e5a4a785/37dc9/2019-11-02-orszaghaz-i.webp 75w,\n/static/36d87329aeeda296ae923606e5a4a785/37a2a/2019-11-02-orszaghaz-i.webp 150w,\n/static/36d87329aeeda296ae923606e5a4a785/40e2f/2019-11-02-orszaghaz-i.webp 300w,\n/static/36d87329aeeda296ae923606e5a4a785/6a707/2019-11-02-orszaghaz-i.webp 450w,\n/static/36d87329aeeda296ae923606e5a4a785/bf714/2019-11-02-orszaghaz-i.webp 600w,\n/static/36d87329aeeda296ae923606e5a4a785/7fe6d/2019-11-02-orszaghaz-i.webp 3708w", - "sizes": "(max-width: 300px) 100vw, 300px" - } - } - } - }, - "fields": { - "slug": "/orszaghaz-i", - "type": "photo" - } - } - }, - { - "node": { - "id": "0549d0c5-1c41-5cf6-b640-6fbc6ab778fb", - "frontmatter": { - "title": "Foro di Cesare", - "image": { - "childImageSharp": { - "original": { - "src": "/static/2019-09-29-foro-di-cesare-00ba7297095683d32f490c1cf1a3ca2d.jpg" - }, - "fluid": { - "aspectRatio": 1, - "src": "/static/00ba7297095683d32f490c1cf1a3ca2d/0f41b/2019-09-29-foro-di-cesare.jpg", - "srcSet": "/static/00ba7297095683d32f490c1cf1a3ca2d/73124/2019-09-29-foro-di-cesare.jpg 75w,\n/static/00ba7297095683d32f490c1cf1a3ca2d/712e7/2019-09-29-foro-di-cesare.jpg 150w,\n/static/00ba7297095683d32f490c1cf1a3ca2d/0f41b/2019-09-29-foro-di-cesare.jpg 300w,\n/static/00ba7297095683d32f490c1cf1a3ca2d/270e8/2019-09-29-foro-di-cesare.jpg 450w,\n/static/00ba7297095683d32f490c1cf1a3ca2d/aa95b/2019-09-29-foro-di-cesare.jpg 600w,\n/static/00ba7297095683d32f490c1cf1a3ca2d/9dbe2/2019-09-29-foro-di-cesare.jpg 2868w", - "srcWebp": "/static/00ba7297095683d32f490c1cf1a3ca2d/40e2f/2019-09-29-foro-di-cesare.webp", - "srcSetWebp": "/static/00ba7297095683d32f490c1cf1a3ca2d/37dc9/2019-09-29-foro-di-cesare.webp 75w,\n/static/00ba7297095683d32f490c1cf1a3ca2d/37a2a/2019-09-29-foro-di-cesare.webp 150w,\n/static/00ba7297095683d32f490c1cf1a3ca2d/40e2f/2019-09-29-foro-di-cesare.webp 300w,\n/static/00ba7297095683d32f490c1cf1a3ca2d/6a707/2019-09-29-foro-di-cesare.webp 450w,\n/static/00ba7297095683d32f490c1cf1a3ca2d/bf714/2019-09-29-foro-di-cesare.webp 600w,\n/static/00ba7297095683d32f490c1cf1a3ca2d/d8318/2019-09-29-foro-di-cesare.webp 2868w", - "sizes": "(max-width: 300px) 100vw, 300px" - } - } - } - }, - "fields": { - "slug": "/foro-di-cesare", - "type": "photo" - } - } - }, - { - "node": { - "id": "fe3ed03e-3612-54cb-aceb-691938b4e3f3", - "frontmatter": { - "title": "Arco di Costantino", - "image": { - "childImageSharp": { - "original": { - "src": "/static/2019-09-29-arco-di-costantino-8f7392d32a0a7746cbb712e4e4a8e2ef.jpg" - }, - "fluid": { - "aspectRatio": 1, - "src": "/static/8f7392d32a0a7746cbb712e4e4a8e2ef/0f41b/2019-09-29-arco-di-costantino.jpg", - "srcSet": "/static/8f7392d32a0a7746cbb712e4e4a8e2ef/73124/2019-09-29-arco-di-costantino.jpg 75w,\n/static/8f7392d32a0a7746cbb712e4e4a8e2ef/712e7/2019-09-29-arco-di-costantino.jpg 150w,\n/static/8f7392d32a0a7746cbb712e4e4a8e2ef/0f41b/2019-09-29-arco-di-costantino.jpg 300w,\n/static/8f7392d32a0a7746cbb712e4e4a8e2ef/270e8/2019-09-29-arco-di-costantino.jpg 450w,\n/static/8f7392d32a0a7746cbb712e4e4a8e2ef/aa95b/2019-09-29-arco-di-costantino.jpg 600w,\n/static/8f7392d32a0a7746cbb712e4e4a8e2ef/30037/2019-09-29-arco-di-costantino.jpg 3024w", - "srcWebp": "/static/8f7392d32a0a7746cbb712e4e4a8e2ef/40e2f/2019-09-29-arco-di-costantino.webp", - "srcSetWebp": "/static/8f7392d32a0a7746cbb712e4e4a8e2ef/37dc9/2019-09-29-arco-di-costantino.webp 75w,\n/static/8f7392d32a0a7746cbb712e4e4a8e2ef/37a2a/2019-09-29-arco-di-costantino.webp 150w,\n/static/8f7392d32a0a7746cbb712e4e4a8e2ef/40e2f/2019-09-29-arco-di-costantino.webp 300w,\n/static/8f7392d32a0a7746cbb712e4e4a8e2ef/6a707/2019-09-29-arco-di-costantino.webp 450w,\n/static/8f7392d32a0a7746cbb712e4e4a8e2ef/bf714/2019-09-29-arco-di-costantino.webp 600w,\n/static/8f7392d32a0a7746cbb712e4e4a8e2ef/859d2/2019-09-29-arco-di-costantino.webp 3024w", - "sizes": "(max-width: 300px) 100vw, 300px" - } - } - } - }, - "fields": { - "slug": "/arco-di-costantino", - "type": "photo" - } - } - }, - { - "node": { - "id": "2cc51eaa-e6c0-521e-8cea-00cf68688161", - "frontmatter": { - "title": "Vatican Museums", - "image": { - "childImageSharp": { - "original": { - "src": "/static/2019-09-28-vatican-museums-9ffc375488247897643811d33d28edf9.jpg" - }, - "fluid": { - "aspectRatio": 1, - "src": "/static/9ffc375488247897643811d33d28edf9/0f41b/2019-09-28-vatican-museums.jpg", - "srcSet": "/static/9ffc375488247897643811d33d28edf9/73124/2019-09-28-vatican-museums.jpg 75w,\n/static/9ffc375488247897643811d33d28edf9/712e7/2019-09-28-vatican-museums.jpg 150w,\n/static/9ffc375488247897643811d33d28edf9/0f41b/2019-09-28-vatican-museums.jpg 300w,\n/static/9ffc375488247897643811d33d28edf9/270e8/2019-09-28-vatican-museums.jpg 450w,\n/static/9ffc375488247897643811d33d28edf9/aa95b/2019-09-28-vatican-museums.jpg 600w,\n/static/9ffc375488247897643811d33d28edf9/179de/2019-09-28-vatican-museums.jpg 2978w", - "srcWebp": "/static/9ffc375488247897643811d33d28edf9/40e2f/2019-09-28-vatican-museums.webp", - "srcSetWebp": "/static/9ffc375488247897643811d33d28edf9/37dc9/2019-09-28-vatican-museums.webp 75w,\n/static/9ffc375488247897643811d33d28edf9/37a2a/2019-09-28-vatican-museums.webp 150w,\n/static/9ffc375488247897643811d33d28edf9/40e2f/2019-09-28-vatican-museums.webp 300w,\n/static/9ffc375488247897643811d33d28edf9/6a707/2019-09-28-vatican-museums.webp 450w,\n/static/9ffc375488247897643811d33d28edf9/bf714/2019-09-28-vatican-museums.webp 600w,\n/static/9ffc375488247897643811d33d28edf9/79bab/2019-09-28-vatican-museums.webp 2978w", - "sizes": "(max-width: 300px) 100vw, 300px" - } - } - } - }, - "fields": { - "slug": "/vatican-museums", - "type": "photo" - } - } - }, - { - "node": { - "id": "9133fd25-1cb8-5660-be11-3532d4e18cae", - "frontmatter": { - "title": "German Chancellery II", - "image": { - "childImageSharp": { - "original": { - "src": "/static/2019-08-18-german-chancellery-ii-325bcee8ced12b150a2f3448ec1ae8cd.jpg" - }, - "fluid": { - "aspectRatio": 1, - "src": "/static/325bcee8ced12b150a2f3448ec1ae8cd/0f41b/2019-08-18-german-chancellery-ii.jpg", - "srcSet": "/static/325bcee8ced12b150a2f3448ec1ae8cd/73124/2019-08-18-german-chancellery-ii.jpg 75w,\n/static/325bcee8ced12b150a2f3448ec1ae8cd/712e7/2019-08-18-german-chancellery-ii.jpg 150w,\n/static/325bcee8ced12b150a2f3448ec1ae8cd/0f41b/2019-08-18-german-chancellery-ii.jpg 300w,\n/static/325bcee8ced12b150a2f3448ec1ae8cd/270e8/2019-08-18-german-chancellery-ii.jpg 450w,\n/static/325bcee8ced12b150a2f3448ec1ae8cd/aa95b/2019-08-18-german-chancellery-ii.jpg 600w,\n/static/325bcee8ced12b150a2f3448ec1ae8cd/0e49e/2019-08-18-german-chancellery-ii.jpg 4032w", - "srcWebp": "/static/325bcee8ced12b150a2f3448ec1ae8cd/40e2f/2019-08-18-german-chancellery-ii.webp", - "srcSetWebp": "/static/325bcee8ced12b150a2f3448ec1ae8cd/37dc9/2019-08-18-german-chancellery-ii.webp 75w,\n/static/325bcee8ced12b150a2f3448ec1ae8cd/37a2a/2019-08-18-german-chancellery-ii.webp 150w,\n/static/325bcee8ced12b150a2f3448ec1ae8cd/40e2f/2019-08-18-german-chancellery-ii.webp 300w,\n/static/325bcee8ced12b150a2f3448ec1ae8cd/6a707/2019-08-18-german-chancellery-ii.webp 450w,\n/static/325bcee8ced12b150a2f3448ec1ae8cd/bf714/2019-08-18-german-chancellery-ii.webp 600w,\n/static/325bcee8ced12b150a2f3448ec1ae8cd/b3fb4/2019-08-18-german-chancellery-ii.webp 4032w", - "sizes": "(max-width: 300px) 100vw, 300px" - } - } - } - }, - "fields": { - "slug": "/german-chancellery-ii", - "type": "photo" - } - } - } - ] - } -} diff --git a/.jest/__fixtures__/link.json b/.jest/__fixtures__/link.json deleted file mode 100644 index e09f93c4..00000000 --- a/.jest/__fixtures__/link.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "post": { - "html": "

An awesome creative idea for a blog post about Web-Design from Joshua Clanton:

\n
\n

Leonardo Da Vinci was one of the greatest artists of the Renaissance, leaving behind a legacy that continues to inspire artists, scientists and others. Here are six things we can learn from him about web design.

\n
", - "excerpt": "An awesome creative idea for a blog post about Web-Design from Joshua Clanton: Leonardo Da Vinci was one of the greatest artists of the…", - "frontmatter": { - "title": "6 Web Design Tips from Leonardo da Vinci", - "image": null, - "toc": null, - "author": "Matthias Kretschmann", - "updated": null, - "tags": ["design"], - "linkurl": "http://designpepper.com/blog/6-web-design-tips-from-leonardo-da-vinci", - "style": null, - "changelog": null - }, - "fields": { - "type": "link", - "slug": "/6-web-design-tips-from-leonardo-da-vinci", - "date": "2008-04-04T18:43:05.000Z", - "githubLink": "https://github.com/kremalicious/blog/tree/main/content/posts/2008-04-04-6-web-design-tips-from-leonardo-da-vinci.md" - }, - "rawMarkdownBody": "\nAn awesome creative idea for a blog post about Web-Design from Joshua Clanton:\n\n> Leonardo Da Vinci was one of the greatest artists of the Renaissance, leaving behind a legacy that continues to inspire artists, scientists and others. Here are six things we can learn from him about web design.\n", - "tableOfContents": "" - } -} diff --git a/.jest/__fixtures__/meta.json b/.jest/__fixtures__/meta.json deleted file mode 100644 index dd3249ab..00000000 --- a/.jest/__fixtures__/meta.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "site": { - "siteMetadata": { - "siteTitle": "kremalicious", - "siteTitleShort": "krlc", - "siteDescription": "Blog of designer & developer Matthias Kretschmann", - "siteUrl": "https://kremalicious.com", - "author": { - "name": "Matthias Kretschmann", - "email": "m@kretschmann.io", - "uri": "https://matthiaskretschmann.com", - "twitter": "https://twitter.com/kremalicious", - "mastodon": "https://mas.to/@krema", - "github": "https://github.com/kremalicious", - "facebook": "https://facebook.com/matthiaskretschmann", - "bitcoin": "171qDmKEXm9YBgBLXyGjjPvopP5o9htQ1V", - "ether": "0x339dbC44d39bf1961E385ed0Ae88FC6069b87Ea1" - }, - "menu": [ - { - "title": "Photos", - "link": "/photos" - }, - { - "title": "Goodies", - "link": "/tags/goodies" - }, - { - "title": "Tags", - "link": "/tags" - } - ], - "rss": "/feed.xml", - "jsonfeed": "/feed.json", - "itemsPerPage": 20, - "repoContentPath": "https://github.com/kremalicious/blog/tree/main/content", - "ad": { - "title": "", - "link": "" - } - } - } -} diff --git a/.jest/__fixtures__/photos.json b/.jest/__fixtures__/photos.json deleted file mode 100644 index c49c6715..00000000 --- a/.jest/__fixtures__/photos.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "allMarkdownRemark": { - "edges": [ - { - "node": { - "id": "6effe45d-0884-527c-9fba-6f7f567979fd", - "frontmatter": { - "title": "Országház II", - "image": { - "childImageSharp": { - "fluid": { - "aspectRatio": 1, - "src": "/static/2dbcf257b4bdf625c24fede935d32425/2423a/2019-11-03-orszaghaz-ii.jpg", - "srcSet": "/static/2dbcf257b4bdf625c24fede935d32425/b7835/2019-11-03-orszaghaz-ii.jpg 100w,\n/static/2dbcf257b4bdf625c24fede935d32425/2de44/2019-11-03-orszaghaz-ii.jpg 200w,\n/static/2dbcf257b4bdf625c24fede935d32425/2423a/2019-11-03-orszaghaz-ii.jpg 400w,\n/static/2dbcf257b4bdf625c24fede935d32425/66039/2019-11-03-orszaghaz-ii.jpg 600w,\n/static/2dbcf257b4bdf625c24fede935d32425/ba820/2019-11-03-orszaghaz-ii.jpg 800w,\n/static/2dbcf257b4bdf625c24fede935d32425/d04d5/2019-11-03-orszaghaz-ii.jpg 3793w", - "srcWebp": "/static/2dbcf257b4bdf625c24fede935d32425/33771/2019-11-03-orszaghaz-ii.webp", - "srcSetWebp": "/static/2dbcf257b4bdf625c24fede935d32425/4f5da/2019-11-03-orszaghaz-ii.webp 100w,\n/static/2dbcf257b4bdf625c24fede935d32425/72345/2019-11-03-orszaghaz-ii.webp 200w,\n/static/2dbcf257b4bdf625c24fede935d32425/33771/2019-11-03-orszaghaz-ii.webp 400w,\n/static/2dbcf257b4bdf625c24fede935d32425/f12d8/2019-11-03-orszaghaz-ii.webp 600w,\n/static/2dbcf257b4bdf625c24fede935d32425/b975c/2019-11-03-orszaghaz-ii.webp 800w,\n/static/2dbcf257b4bdf625c24fede935d32425/f7332/2019-11-03-orszaghaz-ii.webp 3793w", - "sizes": "(max-width: 400px) 100vw, 400px", - "originalImg": "/static/2dbcf257b4bdf625c24fede935d32425/d04d5/2019-11-03-orszaghaz-ii.jpg", - "originalName": "2019-11-03-orszaghaz-ii.jpg", - "presentationWidth": 400, - "presentationHeight": 300 - } - } - } - }, - "fields": { - "slug": "/orszaghaz-ii/", - "type": "photo" - } - } - }, - { - "node": { - "id": "c80697e5-681d-5fcc-9dab-c3a3821ff0b1", - "frontmatter": { - "title": "Országház I", - "image": { - "childImageSharp": { - "fluid": { - "aspectRatio": 1, - "src": "/static/36d87329aeeda296ae923606e5a4a785/2423a/2019-11-02-orszaghaz-i.jpg", - "srcSet": "/static/36d87329aeeda296ae923606e5a4a785/b7835/2019-11-02-orszaghaz-i.jpg 100w,\n/static/36d87329aeeda296ae923606e5a4a785/2de44/2019-11-02-orszaghaz-i.jpg 200w,\n/static/36d87329aeeda296ae923606e5a4a785/2423a/2019-11-02-orszaghaz-i.jpg 400w,\n/static/36d87329aeeda296ae923606e5a4a785/66039/2019-11-02-orszaghaz-i.jpg 600w,\n/static/36d87329aeeda296ae923606e5a4a785/ba820/2019-11-02-orszaghaz-i.jpg 800w,\n/static/36d87329aeeda296ae923606e5a4a785/c9c86/2019-11-02-orszaghaz-i.jpg 3708w", - "srcWebp": "/static/36d87329aeeda296ae923606e5a4a785/33771/2019-11-02-orszaghaz-i.webp", - "srcSetWebp": "/static/36d87329aeeda296ae923606e5a4a785/4f5da/2019-11-02-orszaghaz-i.webp 100w,\n/static/36d87329aeeda296ae923606e5a4a785/72345/2019-11-02-orszaghaz-i.webp 200w,\n/static/36d87329aeeda296ae923606e5a4a785/33771/2019-11-02-orszaghaz-i.webp 400w,\n/static/36d87329aeeda296ae923606e5a4a785/f12d8/2019-11-02-orszaghaz-i.webp 600w,\n/static/36d87329aeeda296ae923606e5a4a785/b975c/2019-11-02-orszaghaz-i.webp 800w,\n/static/36d87329aeeda296ae923606e5a4a785/262c1/2019-11-02-orszaghaz-i.webp 3708w", - "sizes": "(max-width: 400px) 100vw, 400px", - "originalImg": "/static/36d87329aeeda296ae923606e5a4a785/c9c86/2019-11-02-orszaghaz-i.jpg", - "originalName": "2019-11-02-orszaghaz-i.jpg", - "presentationWidth": 400, - "presentationHeight": 297 - } - } - } - }, - "fields": { - "slug": "/orszaghaz-i/", - "type": "photo" - } - } - } - ] - } -} diff --git a/.jest/__fixtures__/post.json b/.jest/__fixtures__/post.json deleted file mode 100644 index fdd44279..00000000 --- a/.jest/__fixtures__/post.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "post": { - "html": "

There are many reasons you might want to browse anonymously which can be accomplished by using Tor. The setup instructions on Tor’s website are quite scattered and outdated so here are some steps to setup Tor on macOS with a simple automated script at the end.

\n

I’m using macOS Catalina (10.15) for the following instructions but it should work on almost any macOS version.

\n

#Tor Browser

\n

\n \n \n \n \n
Tor Browser
\n

\n

The most simple way to surf anonymously with Tor is to just grab Tor Browser. It’s a modified version of Firefox Extended Support Release (ESR) with Tor and some extensions (Torbutton, TorLauncher, NoScript, and HTTPS-Everywhere) built right in. Upon start, Tor Browser automatically starts the required Tor background processes and routes traffic through the Tor network. That’s the way to go if you want the highest level of protection without much further configuration.

\n

But it’s based on an older version of Firefox and there might be more you want to do anonymously on your machine than just browsing the web, like accessing resources via the Terminal or any other app. Or just use the browser you’re used to.

\n

For this you need to have Tor installed on your system and additionally set specific proxy values in your network preferences after you’ve started Tor.

\n
\n

Be aware that the instructions and the script mentioned below will not make whatever you do on the web anonymous. Much depends on your browsing habits, what apps you're using, and none of the methods below will offer the same level of protection than Tor Browser out of the box. You have been warned.

\n
\n

#Install Tor

\n

Contrary to the weirdly outdated install instructions on Tor’s website (hey, remember Macports?), installing Tor on macOS is super simple with Homebrew.

\n

In your Terminal execute:

\n
brew install tor
\n

Then you can start it up by running:

\n
tor
\n

Congratulations, you now have Tor running on your system. But none of your network traffic is routed through it yet.

\n

In order for all your system traffic being routed through Tor you need to adjust your system’s network proxy settings which you can either do visually in the System Preferences or programmatically via macOS’s builtin networksetup.

\n

#Set network proxy settings via System Preferences

\n

You can do this under System Preferences > Network by creating a specific Tor network location for it:

\n
    \n
  1. From Location dropdown at the top, select Edit Locations…
  2. \n
  3. Create a new location by hitting the plus button and name it Tor. Hitting Done will select the new location which is now ready to be configured.
  4. \n
  5. Go to Advanced > Proxies and activate SOCKS Proxy and add those values:
  6. \n
  7. SOCKS proxy server: localhost
  8. \n
  9. Port: 9050
  10. \n
\n

\n \n \n \n \n
Network Settings
\n

\n

After hitting OK & Apply at the initial network screen, you can easily switch to this newly created location from your menu bar under  > Location whenever you start up Tor.

\n

Switching to the Tor location routes all network traffic on your system through Tor. Note that you have to repeat those steps for every other network interface if you use, say, Wi-Fi and Ethernet interchangeably.

\n

#All in one go: start Tor & set network proxy settings automatically

\n

When you’re already in the Terminal to start up Tor, additionally setting the network settings involves a lot of fiddling around. Ain’t nobody got time for that.

\n

Thankfully macOS provides a way to programmatically set those proxy values via the networksetup utility. I’ve found a nice script for this but running it opened multiple admin password prompts. So I extended it a bit to make it more user friendly.

\n

In a nutshell, this shell script asks you for your admin password upfront, starts up Tor, and sets all required proxy network settings automatically:

\n
#!/usr/bin/env bash\n\n# 'Wi-Fi' or 'Ethernet' or 'Display Ethernet'\nINTERFACE=Wi-Fi\n\n# Ask for the administrator password upfront\nsudo -v\n\n# Keep-alive: update existing `sudo` time stamp until finished\nwhile true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null &\n\n# trap ctrl-c and call disable_proxy()\nfunction disable_proxy() {\n    sudo networksetup -setsocksfirewallproxystate $INTERFACE off\n    echo "$(tput setaf 64)" #green\n    echo "SOCKS proxy disabled."\n    echo "$(tput sgr0)" # color reset\n}\ntrap disable_proxy INT\n\n# Let's roll\nsudo networksetup -setsocksfirewallproxy $INTERFACE 127.0.0.1 9050 off\nsudo networksetup -setsocksfirewallproxystate $INTERFACE on\n\necho "$(tput setaf 64)" # green\necho "SOCKS proxy 127.0.0.1:9050 enabled."\necho "$(tput setaf 136)" # orange\necho "Starting Tor..."\necho "$(tput sgr0)" # color reset\n\ntor
\n

Save this script under something like tor.sh in one of your sourced bin folders, make it executable with chmod + x and use it as a replacement for the general tor command. So you can just run

\n
tor.sh
\n

and Tor should run smoothly on your system without additional configuration:

\n

\n \n \n \n \n
Tor running in Terminal
\n

\n

Verify you’re indeed browsing over the Tor network by going to check.torproject.org.

\n

When you’re done, just exit the script with ctrl + c and the network settings will be reverted to their previous configuration.

\n

#Non-standard apps

\n

Some apps are just not good Mac citizens and use their own network settings, ignoring macOS system network proxy settings. E.g. older versions of Google Chrome were using their own custom network settings and therefore were not routing their web traffic through the proxy configured in System Preferences.

\n

But the most recent Chrome version automatically picks up macOS’s native proxy settings, as does the most recent version of Firefox.

\n

Always check your Tor connection with whatever app you’re using and if needed set the proxy preferences manually in the respective app with:

\n\n", - "excerpt": "There are many reasons you might want to browse anonymously which can be accomplished by using Tor. The setup instructions on Tor’s website…", - "frontmatter": { - "title": "Simple Tor setup on macOS", - "image": { - "childImageSharp": { - "fluid": { - "aspectRatio": 3.2, - "src": "/static/c87c817b4191fb48e9ca4419c0c70bb8/3995d/teaser-tor.png", - "srcSet": "/static/c87c817b4191fb48e9ca4419c0c70bb8/f0031/teaser-tor.png 200w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/cad89/teaser-tor.png 400w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/3995d/teaser-tor.png 800w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/32ce4/teaser-tor.png 1200w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/1ed7e/teaser-tor.png 1600w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/19dc3/teaser-tor.png 1920w", - "srcWebp": "/static/c87c817b4191fb48e9ca4419c0c70bb8/240ac/teaser-tor.webp", - "srcSetWebp": "/static/c87c817b4191fb48e9ca4419c0c70bb8/04c4c/teaser-tor.webp 200w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/ebea1/teaser-tor.webp 400w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/240ac/teaser-tor.webp 800w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/823f0/teaser-tor.webp 1200w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/9e49e/teaser-tor.webp 1600w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/68ae1/teaser-tor.webp 1920w", - "sizes": "(max-width: 800px) 100vw, 800px", - "originalImg": "/static/c87c817b4191fb48e9ca4419c0c70bb8/19dc3/teaser-tor.png", - "originalName": "teaser-tor.png", - "presentationWidth": 800, - "presentationHeight": 250 - } - }, - "fields": null - }, - "toc": true, - "author": "Matthias Kretschmann", - "updated": "2019-11-07T22:52:46.000Z", - "tags": ["tutorial", "tor", "macos", "goodies", "apple"], - "linkurl": null, - "style": null, - "changelog": null - }, - "fields": { - "type": "post", - "slug": "/simple-tor-setup-on-mac-os-x", - "date": "2015-08-02T19:57:30.912Z", - "githubLink": "https://github.com/kremalicious/blog/tree/main/content/posts/2015-08-02-simple-tor-setup-on-mac-os-x/index.md" - }, - "rawMarkdownBody": "\nThere are many reasons you might want to browse anonymously which can be accomplished by using [Tor](https://www.torproject.org). The setup instructions on Tor's website are quite scattered and outdated so here are some steps to setup Tor on macOS with a simple automated script at the end.\n\nI'm using macOS Catalina (10.15) for the following instructions but it should work on almost any macOS version.\n\n## Tor Browser\n\n![Tor Browser](tor-browser.png)\n\nThe most simple way to surf anonymously with Tor is to just grab [Tor Browser](https://www.torproject.org/projects/torbrowser.html.en). It's a modified version of [Firefox Extended Support Release (ESR)](https://www.mozilla.org/en-US/firefox/organizations/) with Tor and some extensions (Torbutton, TorLauncher, NoScript, and HTTPS-Everywhere) built right in. Upon start, Tor Browser automatically starts the required Tor background processes and routes traffic through the Tor network. That's the way to go if you want the highest level of protection without much further configuration.\n\nBut it's based on an older version of Firefox and there might be more you want to do anonymously on your machine than just browsing the web, like accessing resources via the Terminal or any other app. Or just use the browser you're used to.\n\nFor this you need to have Tor installed on your system and additionally set specific proxy values in your network preferences after you've started Tor.\n\n
\n

Be aware that the instructions and the script mentioned below will not make whatever you do on the web anonymous. Much depends on your browsing habits, what apps you're using, and none of the methods below will offer the same level of protection than Tor Browser out of the box. You have been warned.

\n
\n\n## Install Tor\n\nContrary to the weirdly outdated [install instructions on Tor's website](https://www.torproject.org/docs/tor-doc-osx.html.en) (hey, remember Macports?), installing Tor on macOS is super simple with [Homebrew](http://brew.sh).\n\nIn your Terminal execute:\n\n```bash\nbrew install tor\n```\n\nThen you can start it up by running:\n\n```bash\ntor\n```\n\nCongratulations, you now have Tor running on your system. But none of your network traffic is routed through it yet.\n\nIn order for all your system traffic being routed through Tor you need to adjust your system's network proxy settings which you can either do visually in the System Preferences or programmatically via macOS's builtin `networksetup`.\n\n## Set network proxy settings via System Preferences\n\nYou can do this under _System Preferences > Network_ by creating a specific Tor network location for it:\n\n1. From Location dropdown at the top, select _Edit Locations..._\n2. Create a new location by hitting the plus button and name it _Tor_. Hitting Done will select the new location which is now ready to be configured.\n3. Go to _Advanced > Proxies_ and activate _SOCKS Proxy_ and add those values:\n\n- _SOCKS proxy server_: `localhost`\n- _Port_: `9050`\n\n![Network Settings](tor-osx-proxy.png)\n\nAfter hitting _OK_ & _Apply_ at the initial network screen, you can easily switch to this newly created location from your menu bar under _ > Location_ whenever you start up Tor.\n\nSwitching to the Tor location routes all network traffic on your system through Tor. Note that you have to repeat those steps for every other network interface if you use, say, Wi-Fi and Ethernet interchangeably.\n\n## All in one go: start Tor & set network proxy settings automatically\n\nWhen you're already in the Terminal to start up Tor, additionally setting the network settings involves a lot of fiddling around. Ain't nobody got time for that.\n\nThankfully macOS provides a way to programmatically set those proxy values via the `networksetup` utility. I've found a [nice script](http://leonid.shevtsov.me/en/an-easy-way-to-use-tor-on-os-x) for this but running it opened multiple admin password prompts. So I extended it a bit to make it more user friendly.\n\nIn a nutshell, this shell script asks you for your admin password upfront, starts up Tor, and sets all required proxy network settings automatically:\n\n```bash\n#!/usr/bin/env bash\n\n# 'Wi-Fi' or 'Ethernet' or 'Display Ethernet'\nINTERFACE=Wi-Fi\n\n# Ask for the administrator password upfront\nsudo -v\n\n# Keep-alive: update existing `sudo` time stamp until finished\nwhile true; do sudo -n true; sleep 60; kill -0 \"$$\" || exit; done 2>/dev/null &\n\n# trap ctrl-c and call disable_proxy()\nfunction disable_proxy() {\n sudo networksetup -setsocksfirewallproxystate $INTERFACE off\n echo \"$(tput setaf 64)\" #green\n echo \"SOCKS proxy disabled.\"\n echo \"$(tput sgr0)\" # color reset\n}\ntrap disable_proxy INT\n\n# Let's roll\nsudo networksetup -setsocksfirewallproxy $INTERFACE 127.0.0.1 9050 off\nsudo networksetup -setsocksfirewallproxystate $INTERFACE on\n\necho \"$(tput setaf 64)\" # green\necho \"SOCKS proxy 127.0.0.1:9050 enabled.\"\necho \"$(tput setaf 136)\" # orange\necho \"Starting Tor...\"\necho \"$(tput sgr0)\" # color reset\n\ntor\n```\n\nSave this script under something like `tor.sh` in one of your sourced `bin` folders, make it executable with `chmod + x` and use it as a replacement for the general `tor` command. So you can just run\n\n```bash\ntor.sh\n```\n\nand Tor should run smoothly on your system without additional configuration:\n\n![Tor running in Terminal](tor-osx-terminal.png)\n\nVerify you're indeed browsing over the Tor network by going to [check.torproject.org](https://check.torproject.org).\n\nWhen you're done, just exit the script with ctrl + c and the network settings will be reverted to their previous configuration.\n\n## Non-standard apps\n\nSome apps are just not good Mac citizens and use their own network settings, ignoring macOS system network proxy settings. E.g. older versions of Google Chrome were using their own custom network settings and therefore were not routing their web traffic through the proxy configured in System Preferences.\n\nBut the most recent Chrome version automatically picks up macOS's native proxy settings, as does the most recent version of Firefox.\n\nAlways [check](https://check.torproject.org) your Tor connection with whatever app you're using and if needed set the proxy preferences manually in the respective app with:\n\n- _SOCKS proxy server_: `localhost`\n- _Port_: `9050`\n", - "tableOfContents": "" - } -} diff --git a/.jest/__fixtures__/postWithMore.json b/.jest/__fixtures__/postWithMore.json deleted file mode 100644 index 2d3255d4..00000000 --- a/.jest/__fixtures__/postWithMore.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "post": { - "html": "

There are many reasons you might want to browse anonymously which can be accomplished by using Tor. The setup instructions on Tor’s website are quite scattered and outdated so here are some steps to setup Tor on macOS with a simple automated script at the end.

\n

I’m using macOS Catalina (10.15) for the following instructions but it should work on almost any macOS version.

\n

#Tor Browser

\n

\n \n \n \n \n
Tor Browser
\n

\n

The most simple way to surf anonymously with Tor is to just grab Tor Browser. It’s a modified version of Firefox Extended Support Release (ESR) with Tor and some extensions (Torbutton, TorLauncher, NoScript, and HTTPS-Everywhere) built right in. Upon start, Tor Browser automatically starts the required Tor background processes and routes traffic through the Tor network. That’s the way to go if you want the highest level of protection without much further configuration.

\n

But it’s based on an older version of Firefox and there might be more you want to do anonymously on your machine than just browsing the web, like accessing resources via the Terminal or any other app. Or just use the browser you’re used to.

\n

For this you need to have Tor installed on your system and additionally set specific proxy values in your network preferences after you’ve started Tor.

\n
\n

Be aware that the instructions and the script mentioned below will not make whatever you do on the web anonymous. Much depends on your browsing habits, what apps you're using, and none of the methods below will offer the same level of protection than Tor Browser out of the box. You have been warned.

\n
\n

#Install Tor

\n

Contrary to the weirdly outdated install instructions on Tor’s website (hey, remember Macports?), installing Tor on macOS is super simple with Homebrew.

\n

In your Terminal execute:

\n
brew install tor
\n

Then you can start it up by running:

\n
tor
\n

Congratulations, you now have Tor running on your system. But none of your network traffic is routed through it yet.

\n

In order for all your system traffic being routed through Tor you need to adjust your system’s network proxy settings which you can either do visually in the System Preferences or programmatically via macOS’s builtin networksetup.

\n

#Set network proxy settings via System Preferences

\n

You can do this under System Preferences > Network by creating a specific Tor network location for it:

\n
    \n
  1. From Location dropdown at the top, select Edit Locations…
  2. \n
  3. Create a new location by hitting the plus button and name it Tor. Hitting Done will select the new location which is now ready to be configured.
  4. \n
  5. Go to Advanced > Proxies and activate SOCKS Proxy and add those values:
  6. \n
  7. SOCKS proxy server: localhost
  8. \n
  9. Port: 9050
  10. \n
\n

\n \n \n \n \n
Network Settings
\n

\n

After hitting OK & Apply at the initial network screen, you can easily switch to this newly created location from your menu bar under  > Location whenever you start up Tor.

\n

Switching to the Tor location routes all network traffic on your system through Tor. Note that you have to repeat those steps for every other network interface if you use, say, Wi-Fi and Ethernet interchangeably.

\n

#All in one go: start Tor & set network proxy settings automatically

\n

When you’re already in the Terminal to start up Tor, additionally setting the network settings involves a lot of fiddling around. Ain’t nobody got time for that.

\n

Thankfully macOS provides a way to programmatically set those proxy values via the networksetup utility. I’ve found a nice script for this but running it opened multiple admin password prompts. So I extended it a bit to make it more user friendly.

\n

In a nutshell, this shell script asks you for your admin password upfront, starts up Tor, and sets all required proxy network settings automatically:

\n
#!/usr/bin/env bash\n\n# 'Wi-Fi' or 'Ethernet' or 'Display Ethernet'\nINTERFACE=Wi-Fi\n\n# Ask for the administrator password upfront\nsudo -v\n\n# Keep-alive: update existing `sudo` time stamp until finished\nwhile true; do sudo -n true; sleep 60; kill -0 "$$" || exit; done 2>/dev/null &\n\n# trap ctrl-c and call disable_proxy()\nfunction disable_proxy() {\n    sudo networksetup -setsocksfirewallproxystate $INTERFACE off\n    echo "$(tput setaf 64)" #green\n    echo "SOCKS proxy disabled."\n    echo "$(tput sgr0)" # color reset\n}\ntrap disable_proxy INT\n\n# Let's roll\nsudo networksetup -setsocksfirewallproxy $INTERFACE 127.0.0.1 9050 off\nsudo networksetup -setsocksfirewallproxystate $INTERFACE on\n\necho "$(tput setaf 64)" # green\necho "SOCKS proxy 127.0.0.1:9050 enabled."\necho "$(tput setaf 136)" # orange\necho "Starting Tor..."\necho "$(tput sgr0)" # color reset\n\ntor
\n

Save this script under something like tor.sh in one of your sourced bin folders, make it executable with chmod + x and use it as a replacement for the general tor command. So you can just run

\n
tor.sh
\n

and Tor should run smoothly on your system without additional configuration:

\n

\n \n \n \n \n
Tor running in Terminal
\n

\n

Verify you’re indeed browsing over the Tor network by going to check.torproject.org.

\n

When you’re done, just exit the script with ctrl + c and the network settings will be reverted to their previous configuration.

\n

#Non-standard apps

\n

Some apps are just not good Mac citizens and use their own network settings, ignoring macOS system network proxy settings. E.g. older versions of Google Chrome were using their own custom network settings and therefore were not routing their web traffic through the proxy configured in System Preferences.

\n

But the most recent Chrome version automatically picks up macOS’s native proxy settings, as does the most recent version of Firefox.

\n

Always check your Tor connection with whatever app you’re using and if needed set the proxy preferences manually in the respective app with:

\n\n", - "excerpt": "There are many reasons you might want to browse anonymously which can be accomplished by using Tor. The setup instructions on Tor’s website…", - "frontmatter": { - "type": "post", - "title": "Simple Tor setup on macOS", - "image": { - "childImageSharp": { - "fluid": { - "aspectRatio": 3.2, - "src": "/static/c87c817b4191fb48e9ca4419c0c70bb8/3995d/teaser-tor.png", - "srcSet": "/static/c87c817b4191fb48e9ca4419c0c70bb8/f0031/teaser-tor.png 200w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/cad89/teaser-tor.png 400w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/3995d/teaser-tor.png 800w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/32ce4/teaser-tor.png 1200w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/1ed7e/teaser-tor.png 1600w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/19dc3/teaser-tor.png 1920w", - "srcWebp": "/static/c87c817b4191fb48e9ca4419c0c70bb8/240ac/teaser-tor.webp", - "srcSetWebp": "/static/c87c817b4191fb48e9ca4419c0c70bb8/04c4c/teaser-tor.webp 200w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/ebea1/teaser-tor.webp 400w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/240ac/teaser-tor.webp 800w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/823f0/teaser-tor.webp 1200w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/9e49e/teaser-tor.webp 1600w,\n/static/c87c817b4191fb48e9ca4419c0c70bb8/68ae1/teaser-tor.webp 1920w", - "sizes": "(max-width: 800px) 100vw, 800px", - "originalImg": "/static/c87c817b4191fb48e9ca4419c0c70bb8/19dc3/teaser-tor.png", - "originalName": "teaser-tor.png", - "presentationWidth": 800, - "presentationHeight": 250 - } - }, - "fields": null - }, - "toc": true, - "author": "Matthias Kretschmann", - "updated": "2019-11-07T22:52:46.000Z", - "tags": ["tutorial", "tor", "macos", "goodies", "apple"], - "linkurl": null, - "style": null, - "changelog": null - }, - "fields": { - "slug": "/simple-tor-setup-on-mac-os-x", - "date": "2015-08-02T19:57:30.912Z", - "githubLink": "https://github.com/kremalicious/blog/tree/main/content/posts/2015-08-02-simple-tor-setup-on-mac-os-x/index.md" - }, - "rawMarkdownBody": "\nThere are many reasons you might want to browse anonymously which can be accomplished by using [Tor](https://www.torproject.org). The setup instructions on Tor's website are quite scattered and outdated so here are some steps to setup Tor on macOS with a simple automated script at the end.\n\nI'm using macOS Catalina (10.15) for the following instructions but it should work on almost any macOS version.\n\n## Tor Browser\n\n![Tor Browser](tor-browser.png)\n\nThe most simple way to surf anonymously with Tor is to just grab [Tor Browser](https://www.torproject.org/projects/torbrowser.html.en). It's a modified version of [Firefox Extended Support Release (ESR)](https://www.mozilla.org/en-US/firefox/organizations/) with Tor and some extensions (Torbutton, TorLauncher, NoScript, and HTTPS-Everywhere) built right in. Upon start, Tor Browser automatically starts the required Tor background processes and routes traffic through the Tor network. That's the way to go if you want the highest level of protection without much further configuration.\n\nBut it's based on an older version of Firefox and there might be more you want to do anonymously on your machine than just browsing the web, like accessing resources via the Terminal or any other app. Or just use the browser you're used to.\n\nFor this you need to have Tor installed on your system and additionally set specific proxy values in your network preferences after you've started Tor.\n\n
\n

Be aware that the instructions and the script mentioned below will not make whatever you do on the web anonymous. Much depends on your browsing habits, what apps you're using, and none of the methods below will offer the same level of protection than Tor Browser out of the box. You have been warned.

\n
\n\n## Install Tor\n\nContrary to the weirdly outdated [install instructions on Tor's website](https://www.torproject.org/docs/tor-doc-osx.html.en) (hey, remember Macports?), installing Tor on macOS is super simple with [Homebrew](http://brew.sh).\n\nIn your Terminal execute:\n\n```bash\nbrew install tor\n```\n\nThen you can start it up by running:\n\n```bash\ntor\n```\n\nCongratulations, you now have Tor running on your system. But none of your network traffic is routed through it yet.\n\nIn order for all your system traffic being routed through Tor you need to adjust your system's network proxy settings which you can either do visually in the System Preferences or programmatically via macOS's builtin `networksetup`.\n\n## Set network proxy settings via System Preferences\n\nYou can do this under _System Preferences > Network_ by creating a specific Tor network location for it:\n\n1. From Location dropdown at the top, select _Edit Locations..._\n2. Create a new location by hitting the plus button and name it _Tor_. Hitting Done will select the new location which is now ready to be configured.\n3. Go to _Advanced > Proxies_ and activate _SOCKS Proxy_ and add those values:\n\n- _SOCKS proxy server_: `localhost`\n- _Port_: `9050`\n\n![Network Settings](tor-osx-proxy.png)\n\nAfter hitting _OK_ & _Apply_ at the initial network screen, you can easily switch to this newly created location from your menu bar under _ > Location_ whenever you start up Tor.\n\nSwitching to the Tor location routes all network traffic on your system through Tor. Note that you have to repeat those steps for every other network interface if you use, say, Wi-Fi and Ethernet interchangeably.\n\n## All in one go: start Tor & set network proxy settings automatically\n\nWhen you're already in the Terminal to start up Tor, additionally setting the network settings involves a lot of fiddling around. Ain't nobody got time for that.\n\nThankfully macOS provides a way to programmatically set those proxy values via the `networksetup` utility. I've found a [nice script](http://leonid.shevtsov.me/en/an-easy-way-to-use-tor-on-os-x) for this but running it opened multiple admin password prompts. So I extended it a bit to make it more user friendly.\n\nIn a nutshell, this shell script asks you for your admin password upfront, starts up Tor, and sets all required proxy network settings automatically:\n\n```bash\n#!/usr/bin/env bash\n\n# 'Wi-Fi' or 'Ethernet' or 'Display Ethernet'\nINTERFACE=Wi-Fi\n\n# Ask for the administrator password upfront\nsudo -v\n\n# Keep-alive: update existing `sudo` time stamp until finished\nwhile true; do sudo -n true; sleep 60; kill -0 \"$$\" || exit; done 2>/dev/null &\n\n# trap ctrl-c and call disable_proxy()\nfunction disable_proxy() {\n sudo networksetup -setsocksfirewallproxystate $INTERFACE off\n echo \"$(tput setaf 64)\" #green\n echo \"SOCKS proxy disabled.\"\n echo \"$(tput sgr0)\" # color reset\n}\ntrap disable_proxy INT\n\n# Let's roll\nsudo networksetup -setsocksfirewallproxy $INTERFACE 127.0.0.1 9050 off\nsudo networksetup -setsocksfirewallproxystate $INTERFACE on\n\necho \"$(tput setaf 64)\" # green\necho \"SOCKS proxy 127.0.0.1:9050 enabled.\"\necho \"$(tput setaf 136)\" # orange\necho \"Starting Tor...\"\necho \"$(tput sgr0)\" # color reset\n\ntor\n```\n\nSave this script under something like `tor.sh` in one of your sourced `bin` folders, make it executable with `chmod + x` and use it as a replacement for the general `tor` command. So you can just run\n\n```bash\ntor.sh\n```\n\nand Tor should run smoothly on your system without additional configuration:\n\n![Tor running in Terminal](tor-osx-terminal.png)\n\nVerify you're indeed browsing over the Tor network by going to [check.torproject.org](https://check.torproject.org).\n\nWhen you're done, just exit the script with ctrl + c and the network settings will be reverted to their previous configuration.\n\n## Non-standard apps\n\nSome apps are just not good Mac citizens and use their own network settings, ignoring macOS system network proxy settings. E.g. older versions of Google Chrome were using their own custom network settings and therefore were not routing their web traffic through the proxy configured in System Preferences.\n\nBut the most recent Chrome version automatically picks up macOS's native proxy settings, as does the most recent version of Firefox.\n\nAlways [check](https://check.torproject.org) your Tor connection with whatever app you're using and if needed set the proxy preferences manually in the respective app with:\n\n- _SOCKS proxy server_: `localhost`\n- _Port_: `9050`\n", - "tableOfContents": "" - } -} diff --git a/.jest/__fixtures__/posts.json b/.jest/__fixtures__/posts.json deleted file mode 100644 index 4dbc52d5..00000000 --- a/.jest/__fixtures__/posts.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "allMarkdownRemark": { - "edges": [ - { - "node": { - "id": "6effe45d-0884-527c-9fba-6f7f567979fd", - "fileAbsolutePath": "/Users/m/Code/blog/content/photos/2019-11-03-orszaghaz-ii.md", - "html": "

Inside the Hungarian Parliament Building in Budapest, Hungary.

", - "excerpt": "Inside the Hungarian Parliament Building in Budapest, Hungary.", - "frontmatter": { - "title": "Országház II", - - "linkurl": null, - "tags": null, - "image": { - "childImageSharp": { - "original": { - "src": "/static/2019-11-03-orszaghaz-ii-2dbcf257b4bdf625c24fede935d32425.jpg" - }, - "fluid": { - "aspectRatio": 2.3255813953488373, - "src": "/static/2dbcf257b4bdf625c24fede935d32425/ef7a0/2019-11-03-orszaghaz-ii.jpg", - "srcSet": "/static/2dbcf257b4bdf625c24fede935d32425/23780/2019-11-03-orszaghaz-ii.jpg 100w,\n/static/2dbcf257b4bdf625c24fede935d32425/02ed9/2019-11-03-orszaghaz-ii.jpg 200w,\n/static/2dbcf257b4bdf625c24fede935d32425/ef7a0/2019-11-03-orszaghaz-ii.jpg 400w,\n/static/2dbcf257b4bdf625c24fede935d32425/ac974/2019-11-03-orszaghaz-ii.jpg 600w,\n/static/2dbcf257b4bdf625c24fede935d32425/12c26/2019-11-03-orszaghaz-ii.jpg 800w,\n/static/2dbcf257b4bdf625c24fede935d32425/24914/2019-11-03-orszaghaz-ii.jpg 3793w", - "srcWebp": "/static/2dbcf257b4bdf625c24fede935d32425/a93fc/2019-11-03-orszaghaz-ii.webp", - "srcSetWebp": "/static/2dbcf257b4bdf625c24fede935d32425/b0720/2019-11-03-orszaghaz-ii.webp 100w,\n/static/2dbcf257b4bdf625c24fede935d32425/f6188/2019-11-03-orszaghaz-ii.webp 200w,\n/static/2dbcf257b4bdf625c24fede935d32425/a93fc/2019-11-03-orszaghaz-ii.webp 400w,\n/static/2dbcf257b4bdf625c24fede935d32425/7c0bb/2019-11-03-orszaghaz-ii.webp 600w,\n/static/2dbcf257b4bdf625c24fede935d32425/d1e4e/2019-11-03-orszaghaz-ii.webp 800w,\n/static/2dbcf257b4bdf625c24fede935d32425/0a478/2019-11-03-orszaghaz-ii.webp 3793w", - "sizes": "(max-width: 400px) 100vw, 400px", - "originalImg": "/static/2dbcf257b4bdf625c24fede935d32425/24914/2019-11-03-orszaghaz-ii.jpg", - "originalName": "2019-11-03-orszaghaz-ii.jpg", - "presentationWidth": 400, - "presentationHeight": 300 - } - } - } - }, - "fields": { - "slug": "/orszaghaz-ii/", - "date": "November 03, 2019", - "type": "photo" - } - } - }, - { - "node": { - "id": "c80697e5-681d-5fcc-9dab-c3a3821ff0b1", - "fileAbsolutePath": "/Users/m/Code/blog/content/photos/2019-11-02-orszaghaz-i.md", - "html": "

The Hungarian Parliament Building seen from across the Danube in Budapest, Hungary.

", - "excerpt": "The Hungarian Parliament Building seen from across the Danube in Budapest, Hungary.", - "frontmatter": { - "title": "Országház I", - "linkurl": null, - "tags": null, - "featured": true, - "image": { - "childImageSharp": { - "original": { - "src": "/static/2019-11-02-orszaghaz-i-36d87329aeeda296ae923606e5a4a785.jpg" - }, - "fluid": { - "aspectRatio": 2.3255813953488373, - "src": "/static/36d87329aeeda296ae923606e5a4a785/ef7a0/2019-11-02-orszaghaz-i.jpg", - "srcSet": "/static/36d87329aeeda296ae923606e5a4a785/23780/2019-11-02-orszaghaz-i.jpg 100w,\n/static/36d87329aeeda296ae923606e5a4a785/02ed9/2019-11-02-orszaghaz-i.jpg 200w,\n/static/36d87329aeeda296ae923606e5a4a785/ef7a0/2019-11-02-orszaghaz-i.jpg 400w,\n/static/36d87329aeeda296ae923606e5a4a785/ac974/2019-11-02-orszaghaz-i.jpg 600w,\n/static/36d87329aeeda296ae923606e5a4a785/12c26/2019-11-02-orszaghaz-i.jpg 800w,\n/static/36d87329aeeda296ae923606e5a4a785/b9e8b/2019-11-02-orszaghaz-i.jpg 3708w", - "srcWebp": "/static/36d87329aeeda296ae923606e5a4a785/a93fc/2019-11-02-orszaghaz-i.webp", - "srcSetWebp": "/static/36d87329aeeda296ae923606e5a4a785/b0720/2019-11-02-orszaghaz-i.webp 100w,\n/static/36d87329aeeda296ae923606e5a4a785/f6188/2019-11-02-orszaghaz-i.webp 200w,\n/static/36d87329aeeda296ae923606e5a4a785/a93fc/2019-11-02-orszaghaz-i.webp 400w,\n/static/36d87329aeeda296ae923606e5a4a785/7c0bb/2019-11-02-orszaghaz-i.webp 600w,\n/static/36d87329aeeda296ae923606e5a4a785/d1e4e/2019-11-02-orszaghaz-i.webp 800w,\n/static/36d87329aeeda296ae923606e5a4a785/730f8/2019-11-02-orszaghaz-i.webp 3708w", - "sizes": "(max-width: 400px) 100vw, 400px", - "originalImg": "/static/36d87329aeeda296ae923606e5a4a785/b9e8b/2019-11-02-orszaghaz-i.jpg", - "originalName": "2019-11-02-orszaghaz-i.jpg", - "presentationWidth": 400, - "presentationHeight": 297 - } - } - } - }, - "fields": { - "slug": "/orszaghaz-i/", - "date": "November 02, 2019", - "type": "photo" - } - } - }, - { - "node": { - "id": "2e2c9611-be7b-5bc0-a72b-6c63e2072b5a", - "fileAbsolutePath": "/Users/m/Code/blog/content/posts/2019-10-24-ocean-protocol-and-ipfs-sitting-in-the-merkle-tree/index.md", - "html": "

IPFS is now integrated into the Ocean Protocol stack, allowing you to take advantage of decentralized asset file hosting.

\n
\n
\n

This article was originally posted on Medium in the Ocean Protocol blog.

\n
\n
\n

#✨ Going Decentralized

\n

With Ocean Protocol, you can use centralized storage services like S3, Azure Storage, or your own On-Premise storage to store and retrieve your asset files through Osmosis drivers in Brizo.

\n

But storing asset files in a centralized service poses multiple problems:

\n\n

Initially created to store and efficiently move scientific data sets, the InterPlanetary File System (IPFS) solves all those issues with its goal of transforming the vastly centralized web into a distributed peer-to-peer network.

\n

Files are distributed among multiple nodes, eliminating the single point of failure, legal, and censorship issues. By using content-based instead of location-based addressing of files, URLs won’t break if files are moved.

\n

So we defined OEP-15 to make the ipfs:// protocol a first-class citizen in the Ocean Protocol stack, allowing you to store asset files on IPFS, and use their native IPFS URLs during the publish process.

\n\n

In short, every component in the Ocean Protocol stack now supports publishing and consuming of asset files stored in IPFS which includes support for native IPFS URLs, referencing files with their Content Identifiers (CIDs).

\n

#⛲️ IPFS in Commons Marketplace

\n

Every file stored on IPFS is public by default, so it made perfect sense using this in our Commons Marketplace first. We went through multiple prototypes to end up with our final setup.

\n

During the publish flow you will find an extended Files section for adding a file from an existing URL, and for adding a local file from your device to IPFS.

\n

\n \n \n - React.createElement('a', { - ...rest, - href: to - }) - ), - StaticQuery: jest.fn(), - useStaticQuery: jest.fn() -} diff --git a/.jest/__mocks__/matchMedia.ts b/.jest/__mocks__/matchMedia.ts deleted file mode 100644 index e4341f4a..00000000 --- a/.jest/__mocks__/matchMedia.ts +++ /dev/null @@ -1,27 +0,0 @@ -const matchMediaMock = Object.defineProperty(window, 'matchMedia', { - writable: true, - value: jest - .fn() - .mockImplementationOnce((query) => ({ - matches: false, - media: query, - onchange: null, - addListener: jest.fn(), // deprecated - removeListener: jest.fn(), // deprecated - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - dispatchEvent: jest.fn() - })) - .mockImplementation((query) => ({ - matches: true, - media: query, - onchange: null, - addListener: jest.fn(), // deprecated - removeListener: jest.fn(), // deprecated - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - dispatchEvent: jest.fn() - })) -}) - -export default matchMediaMock diff --git a/.jest/__mocks__/svgr.js b/.jest/__mocks__/svgr.js deleted file mode 100644 index c1faa04d..00000000 --- a/.jest/__mocks__/svgr.js +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react' - -export default 'SvgrURL' -const SvgrMock = React.forwardRef((props, ref) => ) - -export const ReactComponent = SvgrMock diff --git a/.jest/__mocks__/wagmi.js b/.jest/__mocks__/wagmi.js deleted file mode 100644 index 4872c156..00000000 --- a/.jest/__mocks__/wagmi.js +++ /dev/null @@ -1,72 +0,0 @@ -import { chain as chainOrig } from 'wagmi' - -export function useNetwork() { - return { - activeChain: { - nativeCurrency: { - symbol: 'ETH' - } - } - } -} - -export function useAccount() { - return { - data: { - address: '0x0000000000000000000000000000000000000000' - } - } -} - -export function useSendTransaction() { - return { - data: { - address: '0x0000000000000000000000000000000000000000' - } - } -} - -export function useEnsAvatar() { - return { - data: 'xxx.jpg' - } -} - -export function useEnsName() { - return { - data: 'fguhifgvewtyifgwyufew.eth' - } -} - -export function useBalance() { - return { - data: { formatted: '0.22', symbol: 'ETH' } - } -} - -export function useConnect() { - return { - connect: jest.fn() - } -} - -export function useDisconnect() { - return { - disconnect: jest.fn() - } -} - -export function useProvider() { - return {} -} - -export const chain = chainOrig - -export function createClient() { - return { - queryClient: { - mount: jest.fn(), - unmount: jest.fn() - } - } -} diff --git a/.jest/babel.config.js b/.jest/babel.config.js deleted file mode 100644 index 88b4c6ea..00000000 --- a/.jest/babel.config.js +++ /dev/null @@ -1,4 +0,0 @@ -// this file only exists for Jest -module.exports = { - presets: ['babel-preset-gatsby', '@babel/preset-typescript'] -} diff --git a/.jest/jest.config.js b/.jest/jest.config.js deleted file mode 100644 index ab3f2407..00000000 --- a/.jest/jest.config.js +++ /dev/null @@ -1,58 +0,0 @@ -const esModules = [ - 'unified', - 'vfile', - 'vfile-.+', - 'unist-.+', - 'bail', - 'is-plain-obj', - 'trough', - 'mdast-util-.+', - 'micromark', - 'micromark-.+', - 'parse-entities', - 'character-entities', - 'property-information', - 'comma-separated-tokens', - 'hast-.+', - 'remark-.+', - 'rehype-.+', - 'space-separated-tokens', - 'trim-lines', - 'decode-named-character-reference', - 'ccount', - 'escape-string-regexp', - 'markdown-table', - 'web-namespaces', - '@rainbow-me/rainbowkit', - 'wagmi', - '@wagmi/chains', - '@wagmi/core', - '@wagmi/connectors', - 'viem', - 'devlop' -].join('|') - -module.exports = { - rootDir: '../', - transform: { - '^.+\\.[jt]sx?$': ['babel-jest', { configFile: './.jest/babel.config.js' }] - }, - moduleNameMapper: { - '.+\\.(css|styl|less|sass|scss)$': 'identity-obj-proxy', - '.+\\.(jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': - '/.jest/__mocks__/file.js', - '\\.svg': '/.jest/__mocks__/svgr.js', - '^@reach/router(.*)': '/node_modules/@gatsbyjs/reach-router$1' - }, - testPathIgnorePatterns: ['node_modules', '.cache', 'public', 'coverage'], - transformIgnorePatterns: [ - `node_modules/(?!(gatsby|gatsby-link|gatsby-script|${esModules})/)` - ], - globals: { - __PATH_PREFIX__: '' - }, - setupFiles: ['/.jest/loadershim.js'], - setupFilesAfterEnv: ['/.jest/setup-test-env.ts'], - collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/@types/**/*'], - testEnvironment: 'jsdom' -} diff --git a/.jest/loadershim.js b/.jest/loadershim.js deleted file mode 100644 index 772dcc44..00000000 --- a/.jest/loadershim.js +++ /dev/null @@ -1,3 +0,0 @@ -global.___loader = { - enqueue: jest.fn() -} diff --git a/.jest/setup-test-env.ts b/.jest/setup-test-env.ts deleted file mode 100644 index 4d1b4712..00000000 --- a/.jest/setup-test-env.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as Gatsby from 'gatsby' -import '@testing-library/jest-dom' -import avatar from './__fixtures__/avatar.json' -import github from './__fixtures__/github.json' -import meta from './__fixtures__/meta.json' -import posts from './__fixtures__/posts.json' -import './__mocks__/matchMedia' - -// viem uses TextEncoder and TextDecoder which are not available with jsdom 16+ -import { TextEncoder, TextDecoder } from 'util' -Object.assign(global, { TextDecoder, TextEncoder }) - -const useStaticQuery = jest.spyOn(Gatsby, 'useStaticQuery') - -beforeAll(() => { - useStaticQuery.mockImplementation(() => ({ - ...meta, - ...avatar, - logo: { edges: [{ node: { relativePath: 'apple-touch-icon.png' } }] }, - ...posts, - ...github - })) -}) diff --git a/.jest/testRender.ts b/.jest/testRender.ts deleted file mode 100644 index 041d0f68..00000000 --- a/.jest/testRender.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ReactElement } from 'react' -import { render } from '@testing-library/react' - -const testRender = (component: ReactElement): void => { - it('renders without crashing', () => { - const { container } = render(component) - - expect(container.firstChild).toBeInTheDocument() - }) -} - -export default testRender diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 3fd3e7b4..00000000 --- a/.prettierrc +++ /dev/null @@ -1,18 +0,0 @@ -{ - "semi": false, - "singleQuote": true, - "trailingComma": "none", - "tabWidth": 2, - "endOfLine": "lf", - "importOrder": [ - "^(react/(.*)$)|^(react$)", - "^(gatsby/(.*)$)|^(gatsby$)", - "", - "^[./]" - ], - "importOrderSeparation": false, - "importOrderSortSpecifiers": true, - "importOrderBuiltinModulesToTop": true, - "importOrderMergeDuplicateImports": true, - "importOrderCombineTypeAndValueImports": true -} diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..33df0b2e --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,14 @@ +{ + "semi": false, + "singleQuote": true, + "trailingComma": "none", + "tabWidth": 2, + "endOfLine": "lf", + "plugins": ["prettier-plugin-astro"], + "overrides": [ + { + "files": "*.astro", + "options": { "parser": "astro" } + } + ] +} diff --git a/README.md b/README.md index 78c79318..101719fb 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

- 🍭 My blog built with Gatsby + TypeScript. Neat. + 🍭 My blog built with Astro + TypeScript. Neat.

kremalicious.com @@ -16,20 +16,22 @@ --- - [🎉 Features](#-features) + - [🌅 Image handling](#-image-handling) - [🎆 EXIF extraction](#-exif-extraction) - [💰 Cryptocurrency donation via Web3/MetaMask](#-cryptocurrency-donation-via-web3metamask) - [🔍 Search](#-search) - [🕸 Related Posts](#-related-posts) - [📝 GitHub changelog rendering](#-github-changelog-rendering) - [🌗 Theme Switcher](#-theme-switcher) - - [🏆 SEO component](#-seo-component) - - [gatsby-redirect-from](#gatsby-redirect-from) - - [💎 Importing SVG assets](#-importing-svg-assets) - - [🍬 Typekit component](#-typekit-component) + - [💎 SVG assets as components](#-svg-assets-as-components) + - [`redirect_from`](#redirect_from) + - [RSS \& JSON feeds](#rss--json-feeds) - [✨ Development](#-development) - [🔮 Linting](#-linting) + - [🔮 Type Checking](#-type-checking) - [👩‍🔬 Testing](#-testing) - - [🎈 Add a new post](#-add-a-new-post) +- [🎈 Content creation helpers](#-content-creation-helpers) + - [Add a new post](#add-a-new-post) - [🚚 Deployment](#-deployment) - [S3 Deployment](#s3-deployment) - [🏛 Licenses](#-licenses) @@ -40,119 +42,120 @@ ## 🎉 Features -The whole [blog](https://kremalicious.com) is a React-based Single Page App built with [Gatsby v2](https://www.gatsbyjs.org). +The whole [blog](https://kremalicious.com) is a statically exported site built with [Astro](https://astro.build) and TypeScript. Almost all components are Astro or native Web Components, with some React components loaded client-side. + +Styling happens through a combination of basic global styles and on components level either through CSS modules or CSS in ` +{title ? ({title}) : ''}${innerSVG}` + +export const toInnerSvg = (input: string) => + optimizeSVGNative(input, { + plugins: [ + 'removeDoctype', + 'removeXMLProcInst', + 'removeComments', + 'removeMetadata', + 'removeXMLNS', + 'removeEditorsNSData', + 'cleanupAttrs', + 'minifyStyles', + 'convertStyleToAttrs', + 'cleanupIds', + 'removeRasterImages', + 'removeUselessDefs', + 'cleanupNumericValues', + 'cleanupListOfValues', + 'convertColors', + 'removeUnknownsAndDefaults', + 'removeNonInheritableGroupAttrs', + 'removeUselessStrokeAndFill', + 'removeViewBox', + 'cleanupEnableBackground', + 'removeHiddenElems', + 'removeEmptyText', + 'convertShapeToPath', + 'moveElemsAttrsToGroup', + 'moveGroupAttrsToElems', + 'collapseGroups', + 'convertPathData', + 'convertTransform', + 'removeEmptyAttrs', + 'removeEmptyContainers', + 'mergePaths', + 'removeUnusedNS', + 'sortAttrs', + 'removeTitle', + 'removeDesc', + 'removeDimensions', + 'removeStyleElement', + 'removeScriptElement' + ] + }) + .data.replace(/^]*>|<\/svg>$/g, '') + .replace(/ fill="currentColor"/g, '') + .replace(/ (clip|fill)-rule="evenodd"/g, '') + .replace(/\/>/g, ' />') diff --git a/scripts/create-symlinks.sh b/scripts/create-symlinks.sh new file mode 100755 index 00000000..bbe6107f --- /dev/null +++ b/scripts/create-symlinks.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +paths=( + "content:src/content" + "content/articles/2012-07-16-using-kbd-for-fun-and-profit/_post-kbd.css:public/post-kbd.css" + "src/components/ThemeSwitch/theme.cjs:public/theme.js" +) + +# Initialize a counter for created symlinks +symlink_count=0 + +# Iterate over the array and create symlinks +for path_pair in "${paths[@]}"; do + IFS=":" read -r source target <<< "$path_pair" + + # Check if the target symlink file or directory already exists + if [ -e "$PWD/$target" ]; then + continue + fi + + # Create the symlink if it doesn't exist + ln -s "$PWD/$source" "$PWD/$target" + symlink_count=$((symlink_count + 1)) +done + +echo "✔️ [create-symlinks] Created $symlink_count symlinks." diff --git a/scripts/deploy-s3.sh b/scripts/deploy-s3.sh index c755c793..2e02a3a4 100755 --- a/scripts/deploy-s3.sh +++ b/scripts/deploy-s3.sh @@ -5,42 +5,31 @@ # AWS_SECRET_ACCESS_KEY # AWS_DEFAULT_REGION AWS_S3_BUCKET="kremalicious.com" -SITEMAP_URL="https%3A%2F%2Fkremalicious.com%2Fsitemap.xml" +SITEMAP_URL="https%3A%2F%2Fkremalicious.com%2Fsitemap-index.xml" # set -e; function s3sync { - aws s3 sync ./public s3://"$1" \ + aws s3 sync ./dist s3://"$1" \ --include "*" \ --exclude "*.html" \ + --exclude "*.zip" \ --exclude "sw.js" \ - --exclude "*page-data.json" \ - --exclude "*app-data.json" \ - --exclude "chunk-map.json" \ - --exclude "sitemap.xml" \ - --exclude "feed.xml" \ - --exclude "feed.json" \ - --exclude ".iconstats.json" \ - --exclude "humans.txt" \ - --exclude "robots.txt" \ + --exclude "*.json" \ + --exclude "*.txt" \ --cache-control public,max-age=31536000,immutable \ --delete \ --acl public-read - aws s3 sync ./public s3://"$1" \ + aws s3 sync ./dist s3://"$1" \ --exclude "*" \ --include "*.html" \ + --include "*.zip" \ --include "sw.js" \ - --include "*page-data.json" \ - --include "*app-data.json" \ - --include "chunk-map.json" \ - --include "sitemap.xml" \ - --include "feed.xml" \ - --include "feed.json" \ - --include ".iconstats.json" \ - --include "humans.txt" \ - --include "robots.txt" \ + --include "*.xml" \ + --include "*.json" \ + --include "*.txt" \ --cache-control public,max-age=0,must-revalidate \ --delete \ --acl public-read diff --git a/scripts/move-downloads.test.ts b/scripts/move-downloads.test.ts new file mode 100644 index 00000000..3d5d334c --- /dev/null +++ b/scripts/move-downloads.test.ts @@ -0,0 +1,43 @@ +import { test, expect, vi } from 'vitest' +import fs from 'node:fs/promises' +import path from 'node:path' +import { glob } from 'glob' +import { copyZipFiles } from './move-downloads' +import { fileURLToPath } from 'node:url' +import chalk from 'chalk' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +test('copyZipFiles should copy zip files', async () => { + // Create temporary directories and files + const sourceDir = path.join(__dirname, 'tmp_source') + const destDir = path.join(__dirname, 'tmp_dest') + await fs.mkdir(sourceDir, { recursive: true }) + await fs.mkdir(destDir, { recursive: true }) + await fs.writeFile(path.join(sourceDir, 'file1.zip'), 'content1') + await fs.writeFile(path.join(sourceDir, 'file2.zip'), 'content2') + + const globMock = vi.spyOn(glob, 'sync') + globMock.mockReturnValue(['file1.zip', 'file2.zip']) + + const mockOra = { + start: vi.fn(), + succeed: vi.fn(), + fail: vi.fn() + } + + copyZipFiles(sourceDir, destDir, mockOra as any) + + const file1 = await fs.readFile(path.join(destDir, 'file1.zip'), 'utf-8') + const file2 = await fs.readFile(path.join(destDir, 'file2.zip'), 'utf-8') + expect(file1).toBe('content1') + expect(file2).toBe('content2') + + expect(mockOra.succeed).toHaveBeenCalledWith( + `${chalk.bold('[move-downloads]')} Copied 2 .zip files to ${destDir}` + ) + + // Cleanup + await fs.rm(sourceDir, { recursive: true, force: true }) + await fs.rm(destDir, { recursive: true, force: true }) +}) diff --git a/scripts/move-downloads.ts b/scripts/move-downloads.ts new file mode 100644 index 00000000..257c96ca --- /dev/null +++ b/scripts/move-downloads.ts @@ -0,0 +1,73 @@ +// +// Find all zip files in all article folders +// and copy them to public/get/ folder. +// +import fs from 'node:fs' +import path from 'node:path' +import { glob } from 'glob' +import ora, { type Ora } from 'ora' +import chalk from 'chalk' + +const sourceFolder = './content/articles/' +const destinationFolder = './public/get/' +const filesGlob = '**/*.zip' + +const spinner = ora( + `${chalk.bold('[move-downloads]')} Finding and moving zip files` +).start() + +function removeFolderContents(folderPath: string) { + if (fs.existsSync(folderPath)) { + fs.readdirSync(folderPath).forEach((file) => { + const filePath = path.join(folderPath, file) + if (fs.lstatSync(filePath).isDirectory()) { + removeFolderContents(filePath) + fs.rmdirSync(filePath) + } else { + fs.unlinkSync(filePath) + } + }) + } +} + +export function copyZipFiles( + source: string, + destination: string, + spinner: Ora +) { + // Clean out the destination folder + removeFolderContents(destination) + + // Create the destination folder if it doesn't exist + if (!fs.existsSync(destination)) { + fs.mkdirSync(destination, { recursive: true }) + } + + // Find all files recursively in the source folder + const zipFiles = glob.sync(filesGlob, { cwd: source }) + + zipFiles.forEach((zipFile: string) => { + const sourcePath = path.join(source, zipFile) + const destinationPath = path.join(destination, path.basename(zipFile)) + + try { + // Copy the file to the destination folder + fs.copyFileSync(sourcePath, destinationPath) + } catch (error: any) { + spinner.fail( + `${chalk.bold('[move-downloads]')} Error copying ${zipFile}: ${ + (error as Error).message + }` + ) + return + } + }) + + spinner.succeed( + `${chalk.bold('[move-downloads]')} Copied ${ + zipFiles.length + } .zip files to ${destination}` + ) +} + +copyZipFiles(sourceFolder, destinationFolder, spinner) diff --git a/scripts/new.ts b/scripts/new.ts deleted file mode 100644 index bc4f8877..00000000 --- a/scripts/new.ts +++ /dev/null @@ -1,119 +0,0 @@ -import fastExif from 'fast-exif' -import fs from 'fs-extra' -import iptc from 'node-iptc' -import ora from 'ora' -import path from 'path' -import slugify from 'slugify' - -const templatePath = path.join(__dirname, 'new-article.md') -const templatePathPhoto = path.join(__dirname, 'new-photo.md') -const template = fs.readFileSync(templatePath).toString() -const templatePhoto = fs.readFileSync(templatePathPhoto).toString() - -const spinner = ora('Adding new post').start() - -if (!process.argv[2]) { - spinner.fail('Use the format `npm run new "Title of post"`') -} - -let title = process.argv[2] -const isPhoto = process.argv[2] === 'photo' - -spinner.text = `Adding '${title}'.` - -let titleSlug = slugify(title, { lower: true }) -const postsPath = path.join('.', 'content', 'articles') -const photosPath = path.join('.', 'content', 'photos') - -let date = new Date().toISOString() - -async function getIptc(imagePath: string) { - return new Promise((resolve, reject) => { - fs.readFile(imagePath, (err, data) => { - if (err) reject(err) - const iptcData = iptc(data) - return resolve(iptcData) - }) - }) -} - -async function getExif(imagePath: string) { - let exifData - try { - exifData = await fastExif.read(imagePath, true) - } catch (error) { - return null - } - - let iptcData: any = {} - try { - iptcData = await getIptc(imagePath) - } catch (error) { - return null - } - - return { ...exifData, iptc: { ...iptcData } } -} - -async function createPhotoPost() { - const photo = process.argv[3] - try { - const exifData = await getExif(photo) - title = exifData.iptc.object_name || exifData.iptc.title - titleSlug = slugify(title, { lower: true }) - date = new Date(exifData.exif.DateTimeOriginal).toISOString() - const dateShort = date.slice(0, 10) - const description = exifData.iptc.caption - const fileName = `${dateShort}-${titleSlug}` - const postPhoto = `${photosPath}/${fileName}.md` - - const newContentsPhoto = templatePhoto - .split('TITLE') - .join(title) - .split('SLUG') - .join(titleSlug) - .split('DATE_LONG') - .join(date) - .split('DATE_SHORT') - .join(dateShort) - .split('DESCRIPTION') - .join(description) - - // copy photo file in place - fs.copyFile(photo, `${photosPath}/${fileName}.jpg`, (err) => { - if (err) spinner.fail(`Error copying photo file: ${err}`) - }) - - // create photo post file - fs.appendFile(postPhoto, newContentsPhoto, (err) => { - if (err) spinner.fail(`Error creating photo post: ${err}`) - spinner.succeed(`New photo post '${title}' as '${fileName}.md' created.`) - }) - } catch (error) { - console.error(error.message) - } -} - -if (isPhoto) { - createPhotoPost() -} else { - if (process.argv[3]) { - date = new Date(process.argv[3]).toISOString() - } - - const dateShort = date.slice(0, 10) - const file = `${postsPath}/${dateShort}-${titleSlug}/index.md` - - const newContents = template - .split('TITLE') - .join(title) - .split('SLUG') - .join(titleSlug) - .split('DATE') - .join(date) - - fs.outputFile(file, newContents) - .then(() => fs.readFile(file, 'utf8')) - .then(() => spinner.succeed(`New post '${title}' created.`)) - .catch((err: Error) => spinner.fail(`Error creating post: ${err.message}`)) -} diff --git a/scripts/new/createArticlePost.ts b/scripts/new/createArticlePost.ts new file mode 100644 index 00000000..74c4be75 --- /dev/null +++ b/scripts/new/createArticlePost.ts @@ -0,0 +1,52 @@ +import fs from 'node:fs/promises' +import { existsSync, mkdirSync, readFileSync } from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import slugify from '../../src/lib/slugify.js' +import type { Ora } from 'ora' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const templatePath = path.join(__dirname, 'new-article.md') + +export async function createArticlePost( + dest: string, + spinner: Ora, + title: string, + newDate?: string +) { + let file + const date = newDate + ? new Date(newDate).toISOString() + : new Date().toISOString() + + spinner.text = `Adding '${title}'.` + + try { + const titleSlug = slugify(title) + const dateShort = date.slice(0, 10) + const folderName = `${dateShort}-${titleSlug}` + const destination = `${dest}/${folderName}` + file = `${destination}/index.md` + const template = readFileSync(templatePath).toString() + const newContents = template + .split('TITLE') + .join(title) + .split('SLUG') + .join(titleSlug) + .split('DATE') + .join(date) + + // Create the destination folder if it doesn't exist + if (!existsSync(destination)) { + mkdirSync(destination, { recursive: true }) + } + + // create post file + await fs.appendFile(file, newContents) + spinner.succeed(`New post '${title}' created.`) + } catch (error: any) { + spinner.fail((error as Error).message) + } + + return file +} diff --git a/scripts/new/createPhotoPost.ts b/scripts/new/createPhotoPost.ts new file mode 100644 index 00000000..e2d8c3fc --- /dev/null +++ b/scripts/new/createPhotoPost.ts @@ -0,0 +1,77 @@ +import fs from 'node:fs/promises' +import { existsSync, mkdirSync, readFileSync } from 'node:fs' +import slugify from '../../src/lib/slugify.js' +import { readOutExif } from '../../src/lib/exif/index.js' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import type { Ora } from 'ora' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const templatePathPhoto = path.join(__dirname, 'new-photo.md') + +export async function createPhotoPost( + dest: string, + spinner: Ora, + photo: string, + photoTitle?: string +) { + let title + let titleSlug + let date + let postPhotoFile + + try { + const templatePhoto = readFileSync(templatePathPhoto).toString() + const exifData = await readOutExif(photo) + if (!exifData) throw new Error('No exif data found in image') + const { iptc, exif } = exifData + + title = iptc?.object_name || iptc?.title || photoTitle + if (!title) + throw new Error( + 'No title given. Add to IPTC, or use the format `npm run new photo path/to/photo.jpg "Title of post"' + ) + spinner.text = `Adding '${title}'.` + + titleSlug = slugify(title) + date = new Date(exif?.date).toISOString() + const dateShort = date.slice(0, 10) + const description = iptc?.caption + const keywords = (iptc?.keywords as string[])?.join(`\n - `) + const folderName = `${dateShort}-${titleSlug}` + const destination = `${dest}/${folderName}` + postPhotoFile = `${destination}/index.md` + + const newContentsPhoto = templatePhoto + .split('TITLE') + .join(title) + .split('SLUG') + .join(titleSlug) + .split('DATE_LONG') + .join(date) + .split('DATE_SHORT') + .join(dateShort) + .split('DESCRIPTION') + .join(description) + .split('TAGS') + .join(keywords) + + // Create the destination folder if it doesn't exist + if (!existsSync(destination)) { + mkdirSync(destination, { recursive: true }) + } + + // copy photo file in place + await fs.copyFile(photo, `${destination}/${folderName}.jpg`) + + // create photo post file + await fs.appendFile(postPhotoFile, newContentsPhoto) + spinner.succeed( + `New photo post '${title}' under '${postPhotoFile}' created.` + ) + } catch (error: any) { + spinner.fail((error as Error).message) + } + + return postPhotoFile +} diff --git a/scripts/new/index.test.ts b/scripts/new/index.test.ts new file mode 100644 index 00000000..e9fb1e92 --- /dev/null +++ b/scripts/new/index.test.ts @@ -0,0 +1,78 @@ +import { test, expect, describe, afterEach } from 'vitest' +import { createPhotoPost } from './createPhotoPost' +import { promises as fs } from 'node:fs' +import path from 'node:path' +import type { Ora } from 'ora' +import { createArticlePost } from './createArticlePost' + +const destFolder = path.join('.', 'test/__fixtures__/tmp') + +describe('npm run new', () => { + afterEach(async () => { + await fs.rmdir(destFolder, { recursive: true }) + }) + + // Mock spinner + const spinner = { + text: '', + succeed: (text: string) => { + spinner.text = text + }, + fail: (text: string) => { + spinner.text = text + } + } as Ora + + test('createArticlePost should create a new article post', async () => { + const fixturePath = path.join('.', 'test/__fixtures__/new-article.md') + + const title = 'Hello Test' + const date = '2023-09-10' + const file = await createArticlePost(destFolder, spinner, title, date) + expect(file).toBeDefined() + expect(spinner.text).toContain(`New post 'Hello Test' created.`) + + // Verify that the article post was created + const fileExists = + file && + (await fs + .access(file) + .then(() => true) + .catch(() => false)) + + expect(fileExists).toBe(true) + + // Compare the generated index.md with the fixture new-article.md + const generatedContent = file && (await fs.readFile(file, 'utf8')) + const fixtureContent = await fs.readFile(fixturePath, 'utf8') + expect(generatedContent?.trim()).toBe(fixtureContent.trim()) + }) + + test('createPhotoPost should create a new photo post', async () => { + const photoPath = path.join( + '.', + 'test/__fixtures__/image-with-metadata.jpg' + ) + const fixturePath = path.join('.', 'test/__fixtures__/new-photo.md') + + const postPhotoFile = await createPhotoPost(destFolder, spinner, photoPath) + expect(postPhotoFile).toBeDefined() + + // Verify that the photo post was created + const fileExists = + postPhotoFile && + (await fs + .access(postPhotoFile) + .then(() => true) + .catch(() => false)) + + expect(fileExists).toBe(true) + expect(spinner.text).toContain(`New photo post`) + + // Compare the generated index.md with the fixture new-photo.md + const generatedContent = + postPhotoFile && (await fs.readFile(postPhotoFile, 'utf8')) + const fixtureContent = await fs.readFile(fixturePath, 'utf8') + expect(generatedContent?.trim()).toBe(fixtureContent.trim()) + }) +}) diff --git a/scripts/new/index.ts b/scripts/new/index.ts new file mode 100644 index 00000000..efa83918 --- /dev/null +++ b/scripts/new/index.ts @@ -0,0 +1,26 @@ +import path from 'node:path' +import ora from 'ora' +import { createPhotoPost } from './createPhotoPost.js' +import { createArticlePost } from './createArticlePost.js' + +const postsPath = path.join('.', 'content', 'articles') +const photosPath = path.join('.', 'content', 'photos') +const spinner = ora('Adding new post').start() + +if (!process.argv[2]) { + spinner.fail( + 'Use the format `npm run new "Title of post"` or `npm run new photo path/to/photo.jpg`' + ) +} + +const isPhoto = process.argv[2] === 'photo' + +if (isPhoto) { + const photo = process.argv[3] + const photoTitle = process.argv[4] + createPhotoPost(photosPath, spinner, photo, photoTitle) +} else { + const title = process.argv[2] + const newDate = process.argv[3] + createArticlePost(postsPath, spinner, title, newDate) +} diff --git a/scripts/new-article.md b/scripts/new/new-article.md similarity index 70% rename from scripts/new-article.md rename to scripts/new/new-article.md index 8de58bff..d4dddd81 100644 --- a/scripts/new-article.md +++ b/scripts/new/new-article.md @@ -2,7 +2,7 @@ date: DATE title: TITLE -image: SLUG-teaser.png +image: ./SLUG-teaser.png tags: - tag diff --git a/scripts/new-photo.md b/scripts/new/new-photo.md similarity index 53% rename from scripts/new-photo.md rename to scripts/new/new-photo.md index a1887487..ca624249 100644 --- a/scripts/new-photo.md +++ b/scripts/new/new-photo.md @@ -2,7 +2,10 @@ date: DATE_LONG title: TITLE -image: DATE_SHORT-SLUG.jpg +image: ./DATE_SHORT-SLUG.jpg + +tags: + - TAGS --- DESCRIPTION diff --git a/scripts/redirect-from.test.ts b/scripts/redirect-from.test.ts new file mode 100644 index 00000000..fa1a6a9a --- /dev/null +++ b/scripts/redirect-from.test.ts @@ -0,0 +1,32 @@ +import { test, expect, vi } from 'vitest' +import fs from 'node:fs/promises' +import { Stats } from 'node:fs' +import { findMarkdownFilesWithRedirects } from './redirect-from' + +test('findMarkdownFilesWithRedirects should generate correct redirects', async () => { + const readdirMock = vi.spyOn(fs, 'readdir') + readdirMock.mockResolvedValue(['post1.md', 'post2.md'] as any) + + const statMock = vi.spyOn(fs, 'stat') + statMock.mockResolvedValue({ isFile: () => true } as Stats) + + const readFileMock = vi.spyOn(fs, 'readFile') + readFileMock.mockResolvedValueOnce( + '---\nredirect_from: ["/old1", "/old2"]\nslug: /new1\n---' + ) + readFileMock.mockResolvedValueOnce( + '---\nredirect_from: ["/old3"]\nslug: /new2\n---' + ) + + // Mock fs.writeFile to do nothing + const writeFileMock = vi.spyOn(fs, 'writeFile') + writeFileMock.mockResolvedValue() + + const redirects = await findMarkdownFilesWithRedirects('some/dir') + + expect(redirects).toEqual({ + '/old1': '/new1', + '/old2': '/new1', + '/old3': '/new2' + }) +}) diff --git a/scripts/redirect-from.ts b/scripts/redirect-from.ts new file mode 100644 index 00000000..88f46aac --- /dev/null +++ b/scripts/redirect-from.ts @@ -0,0 +1,76 @@ +// +// astro-redirect-from +// +import fs from 'node:fs/promises' +import path from 'node:path' +import frontmatter from 'front-matter' +import ora from 'ora' +import chalk from 'chalk' + +const contentDir = 'content/' +const outputFilePath = '.config/redirects.json' +let fileCount = 0 + +type Frontmatter = { redirect_from?: string[]; slug?: string } + +const spinner = ora( + `${chalk.bold('[redirect-from]')} Extract redirects` +).start() + +export async function findMarkdownFilesWithRedirects( + dir: string +): Promise<{ [old: string]: string }> { + const redirects: { [old: string]: string } = {} + + async function processDir(currentDir: string) { + const items = await fs.readdir(currentDir, { recursive: true }) + + for (const item of items) { + const itemPath = path.join(currentDir, item) + const stats = await fs.stat(itemPath) + + if ( + stats.isFile() && + item.endsWith('.md') && + !itemPath.includes('links') + ) { + const fileContent = await fs.readFile(itemPath, 'utf-8') + const { attributes }: { attributes: Frontmatter } = + frontmatter(fileContent) + + // construct slug from frontmatter or folder name + const postSlug = + attributes.slug || `/${itemPath.split('/')[2].substring(11)}` + + // Check if the Markdown file has a redirect_from field + if (attributes.redirect_from) { + fileCount++ + const redirectFromSlugs = attributes.redirect_from + for (const slug of redirectFromSlugs) { + // Add entries to the redirects object + redirects[slug] = postSlug + } + } + } + } + } + + await processDir(dir) + return redirects +} + +try { + const redirects = await findMarkdownFilesWithRedirects(contentDir) + const redirectsJSON = JSON.stringify(redirects, null, 2) + + // Write the redirects object to the output file + fs.writeFile(outputFilePath, redirectsJSON, 'utf-8') + + spinner.succeed( + `${chalk.bold('[redirect-from]')} Extracted ${ + Object.keys(redirects).length + } redirects from ${fileCount} files to ${outputFilePath}` + ) +} catch (error: any) { + spinner.fail(`${chalk.bold('[redirect-from]')} ${(error as Error).message}`) +} diff --git a/src/@types/Image.d.ts b/src/@types/Image.d.ts deleted file mode 100644 index b18d0cdc..00000000 --- a/src/@types/Image.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { GatsbyImageProps } from 'gatsby-plugin-image' - -export interface ImageProps extends GatsbyImageProps { - title?: string - original?: { src: string } - className?: string -} diff --git a/src/@types/Post.d.ts b/src/@types/Post.d.ts deleted file mode 100644 index 8269a44b..00000000 --- a/src/@types/Post.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface PageContext { - tag?: string - slug: string - currentPageNumber: number - numPages: number - prevPagePath?: string - nextPagePath?: string -} diff --git a/src/@types/css.d.ts b/src/@types/css.d.ts deleted file mode 100644 index 6c344ed3..00000000 --- a/src/@types/css.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module '*.module.css' diff --git a/src/@types/node_modules.d.ts b/src/@types/dmsdec/index.d.ts similarity index 63% rename from src/@types/node_modules.d.ts rename to src/@types/dmsdec/index.d.ts index 6a834d57..517a478b 100644 --- a/src/@types/node_modules.d.ts +++ b/src/@types/dmsdec/index.d.ts @@ -1,8 +1,3 @@ -declare module 'pigeon-maps' -declare module 'pigeon-marker' -declare module 'unified' -declare module 'node-iptc' - declare module 'dms2dec' { export default function dms2dec( lat: readonly number[], diff --git a/src/@types/global.d.ts b/src/@types/global.d.ts index 3eb792c0..df1e7dce 100644 --- a/src/@types/global.d.ts +++ b/src/@types/global.d.ts @@ -1,12 +1,3 @@ -declare module '*.svg' { - import * as React from 'react' - export const ReactComponent: React.FunctionComponent< - React.SVGProps - > - const src: string - export default src -} - interface Window { __LUNR__: { readonly [language: string]: { diff --git a/src/@types/node-iptc/index.d.ts b/src/@types/node-iptc/index.d.ts new file mode 100644 index 00000000..1e532094 --- /dev/null +++ b/src/@types/node-iptc/index.d.ts @@ -0,0 +1,71 @@ +declare module 'node-iptc' { + export default function iptc(buffer: Buffer): IptcData +} + +type IptcData = { + object_type_reference?: string + object_attribute_reference?: string + object_name?: string + edit_status?: string + editorial_update?: string + urgency?: string + subject_reference?: string + category?: string + supplemental_categories?: string[] + fixture_id?: string[] + keywords?: string[] + content_location_code?: string[] + content_location_name?: string[] + release_date?: string + release_time?: string + expiration_date?: string + expiration_time?: string + special_instructions?: string + action_advised?: string + reference_service?: string[] + reference_date?: string[] + reference_number?: string[] + date_created?: string + time_created?: string + digital_date_created?: string + digital_time_created?: string + originating_program?: string + program_version?: string + object_cycle?: string + by_line?: string[] + caption?: string // not in spec, but observed in situ + by_line_title?: string[] + city?: string + sub_location?: string + province_or_state?: string + country_or_primary_location_code?: string + country_or_primary_location_name?: string + original_transmission_reference?: string + headline?: string + credit?: string + source?: string + copyright_notice?: string + contact?: string + local_caption?: string + caption_writer?: string[] + rasterized_caption?: string + image_type?: string + image_orientation?: string + language_identifier?: string + audio_type?: string + audio_sampling_rate?: string + audio_sampling_resolution?: string + audio_duration?: string + audio_outcue?: string + + job_id?: string + master_document_id?: string + short_document_id?: string + unique_document_id?: string + owner_id?: string + + object_preview_file_format?: string + object_preview_file_format_version?: string + object_preview_data?: string + date_time?: Date +} diff --git a/src/components/BackButton.astro b/src/components/BackButton.astro new file mode 100644 index 00000000..931c4fd0 --- /dev/null +++ b/src/components/BackButton.astro @@ -0,0 +1,24 @@ +--- +import { ChevronLeft } from '@images/components' +--- + + + + + + diff --git a/src/components/Changelog/index.astro b/src/components/Changelog/index.astro new file mode 100644 index 00000000..2367d396 --- /dev/null +++ b/src/components/Changelog/index.astro @@ -0,0 +1,50 @@ +--- +import { markdownToHtml } from '@lib/markdown' +import { getRepo } from '@lib/github' +import styles from './index.module.css' + +type Props = { + repo: string +} + +const { repo } = Astro.props as Props +const repoInfo = await getRepo(repo) +if (!repoInfo) { + console.info(`Repo ${repo} not found`) + return +} +const { url, owner, object } = repoInfo +const changelogHtml = await markdownToHtml( + object.text.replace('### Changelog', '') +) +--- + +{ + repoInfo ? ( + <> +

Changelog

+
+

+ sourced from{' '} + + {`${owner?.login}/${repo}:CHANGELOG.md`} + +

+
+
+ + + ) : null +} + + diff --git a/src/components/atoms/Changelog.module.css b/src/components/Changelog/index.module.css similarity index 81% rename from src/components/atoms/Changelog.module.css rename to src/components/Changelog/index.module.css index 810f708f..92b5d2fd 100644 --- a/src/components/atoms/Changelog.module.css +++ b/src/components/Changelog/index.module.css @@ -1,7 +1,14 @@ -.content { +.changelog { padding-left: calc(var(--spacer) / 2); margin-left: calc(var(--spacer) / 2); - border-left: var(--stroke-width) solid var(--border-color); + border-left: var(--border-width) solid var(--border-color); + max-height: 800px; + overflow: hidden; + padding-bottom: var(--spacer); +} + +.changelog:global(.all) { + max-height: none; } .content h2, @@ -19,7 +26,7 @@ height: 0.5rem; border-radius: 50%; display: inline-block; - background: var(--color-headings); + background: var(--border-color); position: absolute; left: -1.275rem; top: calc(var(--font-size-large) / 3); @@ -58,7 +65,7 @@ } .source { - font-size: var(--font-size-mini); + font-size: var(--font-size-small); font-family: var(--font-family-base); font-weight: var(--font-weight-base); padding-bottom: calc(var(--spacer) / 2); @@ -74,7 +81,7 @@ } .source code { - font-size: calc(var(--font-size-mini) * 0.9); + font-size: calc(var(--font-size-small) * 0.9); } .source a:hover { diff --git a/src/components/Copy.astro b/src/components/Copy.astro new file mode 100644 index 00000000..a1e684a7 --- /dev/null +++ b/src/components/Copy.astro @@ -0,0 +1,63 @@ +--- +import { Copy as CopyIcon } from '@images/components' + +type Props = { + text: string +} + +const { text } = Astro.props as Props +--- + + + + + + + + diff --git a/src/components/atoms/Divider.module.css b/src/components/Divider.module.css similarity index 85% rename from src/components/atoms/Divider.module.css rename to src/components/Divider.module.css index e22babeb..116f698e 100644 --- a/src/components/atoms/Divider.module.css +++ b/src/components/Divider.module.css @@ -13,6 +13,6 @@ border-bottom: 1px dashed #fff; } -:global(.dark) .divider::before { +:global([data-theme='dark']) .divider::before { border-bottom-color: var(--brand-grey); } diff --git a/src/components/Donation/Coin.astro b/src/components/Donation/Coin.astro new file mode 100644 index 00000000..882b506f --- /dev/null +++ b/src/components/Donation/Coin.astro @@ -0,0 +1,42 @@ +--- +import Copy from '@components/Copy.astro' + +type Props = { + address: string + title: string +} + +const { address, title }: Props = Astro.props +--- + + + +
+

{title}

+
+ {address} + +
+
diff --git a/src/components/Donation/Web3.tsx b/src/components/Donation/Web3.tsx new file mode 100644 index 00000000..b0676b41 --- /dev/null +++ b/src/components/Donation/Web3.tsx @@ -0,0 +1,15 @@ +import Web3Donation from '@components/Donation/Web3Donation' +import config from '@config/blog.config.ts' +import { RainbowKitProvider } from '@rainbow-me/rainbowkit' +import { WagmiConfig } from 'wagmi' +import { wagmiConfig, chains, theme } from '@lib/rainbowkit' + +export default function Web3() { + return ( + + + + + + ) +} diff --git a/src/components/molecules/Web3Donation/Alert.module.css b/src/components/Donation/Web3Donation/Alert.module.css similarity index 100% rename from src/components/molecules/Web3Donation/Alert.module.css rename to src/components/Donation/Web3Donation/Alert.module.css diff --git a/src/components/molecules/Web3Donation/Alert.test.tsx b/src/components/Donation/Web3Donation/Alert.test.tsx similarity index 88% rename from src/components/molecules/Web3Donation/Alert.test.tsx rename to src/components/Donation/Web3Donation/Alert.test.tsx index 959fc986..a3204dee 100644 --- a/src/components/molecules/Web3Donation/Alert.test.tsx +++ b/src/components/Donation/Web3Donation/Alert.test.tsx @@ -1,5 +1,5 @@ -import React from 'react' import { render } from '@testing-library/react' +import { describe, it } from 'vitest' import Alert from './Alert' describe('Alert', () => { diff --git a/src/components/molecules/Web3Donation/Alert.tsx b/src/components/Donation/Web3Donation/Alert.tsx similarity index 83% rename from src/components/molecules/Web3Donation/Alert.tsx rename to src/components/Donation/Web3Donation/Alert.tsx index b3dc4f90..f9fe120d 100644 --- a/src/components/molecules/Web3Donation/Alert.tsx +++ b/src/components/Donation/Web3Donation/Alert.tsx @@ -1,5 +1,5 @@ -import React, { ReactElement } from 'react' -import * as styles from './Alert.module.css' +import { type ReactElement } from 'react' +import styles from './Alert.module.css' export function getTransactionMessage(transactionHash?: string): { [key: string]: string @@ -38,9 +38,9 @@ export default function Alert({ }): ReactElement { return (
) diff --git a/src/components/molecules/Web3Donation/Conversion.module.css b/src/components/Donation/Web3Donation/Conversion.module.css similarity index 72% rename from src/components/molecules/Web3Donation/Conversion.module.css rename to src/components/Donation/Web3Donation/Conversion.module.css index b241f8bf..cf0ca5a0 100644 --- a/src/components/molecules/Web3Donation/Conversion.module.css +++ b/src/components/Donation/Web3Donation/Conversion.module.css @@ -2,8 +2,8 @@ font-size: var(--font-size-mini); color: var(--text-color-light); text-align: left; - margin-top: calc(var(--spacer) / 4); - margin-left: calc(var(--spacer) * 1.4); + margin-top: 0; + margin-left: calc(var(--spacer) * 2.4); animation: fadeIn 0.5s 0.8s ease-out backwards; } diff --git a/src/components/molecules/Web3Donation/Conversion.test.tsx b/src/components/Donation/Web3Donation/Conversion.test.tsx similarity index 66% rename from src/components/molecules/Web3Donation/Conversion.test.tsx rename to src/components/Donation/Web3Donation/Conversion.test.tsx index d0cef61c..6f386b8d 100644 --- a/src/components/molecules/Web3Donation/Conversion.test.tsx +++ b/src/components/Donation/Web3Donation/Conversion.test.tsx @@ -1,9 +1,9 @@ -import React from 'react' import { render } from '@testing-library/react' +import { describe, it } from 'vitest' import Conversion from './Conversion' describe('Conversion', () => { it('renders without crashing', async () => { - render() + render() }) }) diff --git a/src/components/molecules/Web3Donation/Conversion.tsx b/src/components/Donation/Web3Donation/Conversion.tsx similarity index 61% rename from src/components/molecules/Web3Donation/Conversion.tsx rename to src/components/Donation/Web3Donation/Conversion.tsx index dee0f366..60c03571 100644 --- a/src/components/molecules/Web3Donation/Conversion.tsx +++ b/src/components/Donation/Web3Donation/Conversion.tsx @@ -1,17 +1,16 @@ -import React, { ReactElement, useEffect, useState } from 'react' -import axios from 'axios' -import { useNetwork } from 'wagmi' -import * as styles from './Conversion.module.css' +import { type ReactElement, useEffect, useState } from 'react' +import styles from './Conversion.module.css' export async function getFiat( amount: number, tokenId = 'ethereum' ): Promise<{ [key: string]: string }> { const url = `https://api.coingecko.com/api/v3/simple/price?ids=${tokenId}&vs_currencies=eur%2Cusd` - const response = await axios(url) + const response = await fetch(url) + const json = await response.json() - if (!response) console.error(response.statusText) - const { usd, eur } = response.data[tokenId] + if (!json) console.error(response.statusText) + const { usd, eur } = json[tokenId] const dollar = (amount * usd).toFixed(2) const euro = (amount * eur).toFixed(2) @@ -19,12 +18,12 @@ export async function getFiat( } export default function Conversion({ - amount + amount, + symbol }: { amount: string + symbol: string }): ReactElement { - const { chain } = useNetwork() - const [conversion, setConversion] = useState({ euro: '0.00', dollar: '0.00' @@ -32,23 +31,18 @@ export default function Conversion({ const { dollar, euro } = conversion useEffect(() => { - if (!chain?.nativeCurrency?.symbol) return - async function getFiatResponse() { try { - const tokenId = - chain?.nativeCurrency?.symbol === 'MATIC' - ? 'matic-network' - : 'ethereum' + const tokenId = symbol === 'MATIC' ? 'matic-network' : 'ethereum' const { dollar, euro } = await getFiat(Number(amount), tokenId) setConversion({ euro, dollar }) } catch (error) { - console.error(error.message) + console.error((error as Error).message) } } getFiatResponse() - }, [amount, chain?.nativeCurrency?.symbol]) + }, [amount, symbol]) return (
diff --git a/src/components/molecules/Web3Donation/InputGroup.module.css b/src/components/Donation/Web3Donation/InputGroup.module.css similarity index 95% rename from src/components/molecules/Web3Donation/InputGroup.module.css rename to src/components/Donation/Web3Donation/InputGroup.module.css index 0ed1d61c..9e1d324c 100644 --- a/src/components/molecules/Web3Donation/InputGroup.module.css +++ b/src/components/Donation/Web3Donation/InputGroup.module.css @@ -64,7 +64,7 @@ margin-left: -1rem; } -:global(.dark) .inputInput { +:global([data-theme='dark']) .inputInput { border-color: var(--border-color); } @@ -83,7 +83,7 @@ align-items: center; } -:global(.dark) .currency { +:global([data-theme='dark']) .currency { border-right-color: #000; } diff --git a/src/components/Donation/Web3Donation/InputGroup.test.tsx b/src/components/Donation/Web3Donation/InputGroup.test.tsx new file mode 100644 index 00000000..bf735179 --- /dev/null +++ b/src/components/Donation/Web3Donation/InputGroup.test.tsx @@ -0,0 +1,39 @@ +import { fireEvent, render, screen } from '@testing-library/react' +import { describe, it, expect, vi } from 'vitest' +import InputGroup from './InputGroup' + +const setAmount = vi.fn() + +describe('InputGroup', () => { + it('renders without crashing', async () => { + render( + + ) + + const input = await screen.findByRole('textbox') + const button = await screen.findByRole('button') + fireEvent.change(input, { target: { value: '3' } }) + fireEvent.click(button) + expect(setAmount).toHaveBeenCalled() + }) + + it('renders disabled', async () => { + render( + + ) + + const input = await screen.findByRole('textbox') + expect(input).toBeDefined() + expect(input.attributes.getNamedItem('disabled')).toBeDefined() + }) +}) diff --git a/src/components/molecules/Web3Donation/InputGroup.tsx b/src/components/Donation/Web3Donation/InputGroup.tsx similarity index 59% rename from src/components/molecules/Web3Donation/InputGroup.tsx rename to src/components/Donation/Web3Donation/InputGroup.tsx index 0468455d..ad192a94 100644 --- a/src/components/molecules/Web3Donation/InputGroup.tsx +++ b/src/components/Donation/Web3Donation/InputGroup.tsx @@ -1,19 +1,19 @@ -import React, { ReactElement } from 'react' -import { useAccount, useNetwork } from 'wagmi' -import Input from '../../atoms/Input' +import { type ReactElement } from 'react' +import Input from '@components/Input' import Conversion from './Conversion' -import * as styles from './InputGroup.module.css' +import styles from './InputGroup.module.css' export default function InputGroup({ amount, + isDisabled, + symbol, setAmount }: { amount: string + isDisabled: boolean + symbol: string setAmount(amount: string): void }): ReactElement { - const { address } = useAccount() - const { chain } = useNetwork() - return ( <>
@@ -25,17 +25,17 @@ export default function InputGroup({ value={amount} onChange={(e) => setAmount(e.target.value)} className={styles.inputInput} - disabled={!address} + disabled={isDisabled} />
- {chain?.nativeCurrency?.symbol || 'ETH'} + {symbol}
-
- + ) } diff --git a/src/components/molecules/Web3Donation/index.module.css b/src/components/Donation/Web3Donation/index.module.css similarity index 77% rename from src/components/molecules/Web3Donation/index.module.css rename to src/components/Donation/Web3Donation/index.module.css index 05a3d627..0258b31f 100644 --- a/src/components/molecules/Web3Donation/index.module.css +++ b/src/components/Donation/Web3Donation/index.module.css @@ -1,9 +1,9 @@ .web3 { - composes: container from '../../Layout.module.css'; - max-width: 20rem; - margin-bottom: calc(var(--spacer) * 2); + margin-left: auto; + margin-right: auto; + max-width: 25rem; + width: 100%; text-align: center; - min-height: 165px; } .web3 > div:first-child { @@ -13,6 +13,12 @@ margin-bottom: var(--spacer); } +/* connect button */ +.web3 > div:first-child > button:only-child { + margin-left: auto; + margin-right: auto; +} + .message { font-size: var(--font-size-small); position: relative; diff --git a/src/components/Donation/Web3Donation/index.test.tsx b/src/components/Donation/Web3Donation/index.test.tsx new file mode 100644 index 00000000..815c0899 --- /dev/null +++ b/src/components/Donation/Web3Donation/index.test.tsx @@ -0,0 +1,27 @@ +import { test, expect } from 'vitest' +import { render, fireEvent, screen, waitFor } from '@testing-library/react' +import Web3Donation from '.' + +test('Web3Donation component', async () => { + render() + + const submitButton = screen.getByRole('button') + expect(submitButton).toBeInTheDocument() + + const connectButton = screen.getByText('Connect Wallet') + expect(connectButton).toBeInTheDocument() + + const input = screen.getByRole('textbox') + expect(input).toBeInTheDocument() + + fireEvent.change(input, { target: { value: '1' } }) + expect(input).toHaveValue('1') + + // Simulate form submission + fireEvent.click(submitButton) + + await waitFor(() => { + const alert = screen.getByText(/Waiting for network confirmation/i) + expect(alert).toBeInTheDocument() + }) +}) diff --git a/src/components/molecules/Web3Donation/index.tsx b/src/components/Donation/Web3Donation/index.tsx similarity index 70% rename from src/components/molecules/Web3Donation/index.tsx rename to src/components/Donation/Web3Donation/index.tsx index 41dd86ff..01f5a8f0 100644 --- a/src/components/molecules/Web3Donation/index.tsx +++ b/src/components/Donation/Web3Donation/index.tsx @@ -1,19 +1,27 @@ -import React, { ReactElement, useState } from 'react' +import { type ReactElement, useState } from 'react' import { useDebounce } from 'use-debounce' import { parseEther } from 'viem' -import { usePrepareSendTransaction, useSendTransaction } from 'wagmi' +import { + useAccount, + useNetwork, + usePrepareSendTransaction, + useSendTransaction +} from 'wagmi' import { ConnectButton } from '@rainbow-me/rainbowkit' import Alert, { getTransactionMessage } from './Alert' import InputGroup from './InputGroup' -import * as styles from './index.module.css' +import styles from './index.module.css' export default function Web3Donation({ address }: { address: string }): ReactElement { - const [amount, setAmount] = useState('0.01') + const { address: account } = useAccount() + const { chain } = useNetwork() + + const [amount, setAmount] = useState('0.005') const [debouncedAmount] = useDebounce(amount, 500) const { config } = usePrepareSendTransaction({ @@ -33,10 +41,10 @@ export default function Web3Donation({ }) try { - const result = await sendTransactionAsync() + const result = sendTransactionAsync && (await sendTransactionAsync()) if (isError) { - throw new Error(null) + throw new Error(undefined) } setTransactionHash(result?.hash) @@ -52,10 +60,12 @@ export default function Web3Donation({ }) } } catch (error) { - setMessage(null) + setMessage(undefined) } } + const isDisabled = !account + return (
) : ( - + )} ) diff --git a/src/components/Exif/ExifData.astro b/src/components/Exif/ExifData.astro new file mode 100644 index 00000000..979450bf --- /dev/null +++ b/src/components/Exif/ExifData.astro @@ -0,0 +1,15 @@ +--- +type Props = { + title: string + value: string + icon: any +} + +const { title, value, icon } = Astro.props +const Icon = icon +--- + + + + {value} + diff --git a/src/components/Exif/ExifMap.test.tsx b/src/components/Exif/ExifMap.test.tsx new file mode 100644 index 00000000..06dbd726 --- /dev/null +++ b/src/components/Exif/ExifMap.test.tsx @@ -0,0 +1,20 @@ +import { describe, it } from 'vitest' +import { render, screen } from '@testing-library/react' +import ExifMap from './ExifMap' + +describe('ExifMap', () => { + it('renders without crashing', async () => { + render( + + + + + + + ) + + await screen.findByText(/wheel to zoom/) + }) +}) diff --git a/src/components/Exif/ExifMap.tsx b/src/components/Exif/ExifMap.tsx new file mode 100644 index 00000000..9be73fb5 --- /dev/null +++ b/src/components/Exif/ExifMap.tsx @@ -0,0 +1,57 @@ +import { type ReactElement, useState, useEffect } from 'react' +import { Map, Marker } from 'pigeon-maps' + +const mapbox = + (mapboxId: string) => (x: string, y: string, z: string, dpr: number) => + `https://api.mapbox.com/styles/v1/mapbox/${mapboxId}/tiles/256/${z}/${x}/${y}${ + dpr >= 2 ? '@2x' : '' + }?access_token=${import.meta.env.PUBLIC_MAPBOX_ACCESS_TOKEN}` + +const providers = { + light: mapbox('light-v10'), + dark: mapbox('dark-v10') +} + +type Theme = 'light' | 'dark' + +export default function ExifMap({ + gps +}: { + gps: { latitude: number; longitude: number } +}): ReactElement { + const theme = document?.documentElement?.getAttribute('data-theme') as Theme + + const [zoom, setZoom] = useState(12) + const [provider, setProvider] = useState(() => providers[theme || 'dark']) + + function handleThemeChange() { + const theme = document.documentElement.getAttribute('data-theme') as Theme + setProvider(() => providers[theme]) + } + + useEffect(() => { + if (!window) return + + const toggle = document.querySelector('#toggle') as HTMLInputElement + toggle.addEventListener('change', handleThemeChange) + return () => toggle.removeEventListener('change', handleThemeChange) + }, []) + + const zoomIn = () => setZoom(Math.min(zoom + 4, 20)) + const { latitude, longitude } = gps + + return ( + + + + ) +} diff --git a/src/components/Exif/index.astro b/src/components/Exif/index.astro new file mode 100644 index 00000000..66399e04 --- /dev/null +++ b/src/components/Exif/index.astro @@ -0,0 +1,47 @@ +--- +import type { Exif } from '@lib/exif/types' +import { + Camera, + Crosshair, + Aperture, + Stopwatch, + Sun, + Maximize +} from '@images/components' +import ExifData from './ExifData.astro' +import styles from './index.module.css' +import ExifMap from './ExifMap.tsx' + +type Props = { + exif: Exif +} + +const { model, focalLength, fstop, shutterspeed, exposure, iso, gps } = + Astro.props.exif.exif +--- + + diff --git a/src/components/atoms/Exif.module.css b/src/components/Exif/index.module.css similarity index 89% rename from src/components/atoms/Exif.module.css rename to src/components/Exif/index.module.css index c9387ba6..054a282b 100644 --- a/src/components/atoms/Exif.module.css +++ b/src/components/Exif/index.module.css @@ -1,5 +1,4 @@ .exif { - margin-top: -3rem; margin-bottom: calc(var(--spacer) * 2); } @@ -48,8 +47,8 @@ } .map { - composes: breakout from '../Layout.module.css'; - composes: frame from './Image.module.css'; + composes: breakout from '@layouts/Base/index.module.css'; + composes: frame from '@components/Picture/index.module.css'; height: 220px; margin-top: calc(var(--spacer) * 2); } diff --git a/src/components/Footer/Networks.astro b/src/components/Footer/Networks.astro new file mode 100644 index 00000000..24028c8c --- /dev/null +++ b/src/components/Footer/Networks.astro @@ -0,0 +1,30 @@ +--- +import styles from './Networks.module.css' +import { Twitter, Rss, Mastodon, Github, Jsonfeed } from '@images/components' + +type Props = { + links: string[] +} + +const { links } = Astro.props +--- + +

+ { + links.map((link: string) => ( + + {link.includes('mas.to') ? ( + + ) : link.includes('twitter') ? ( + + ) : link.includes('github') ? ( + + ) : link.includes('feed.xml') ? ( + + ) : link.includes('feed.json') ? ( + + ) : null} + + )) + } +

diff --git a/src/components/molecules/Networks.module.css b/src/components/Footer/Networks.module.css similarity index 100% rename from src/components/molecules/Networks.module.css rename to src/components/Footer/Networks.module.css diff --git a/src/components/Footer/Vcard.astro b/src/components/Footer/Vcard.astro new file mode 100644 index 00000000..7f83d58c --- /dev/null +++ b/src/components/Footer/Vcard.astro @@ -0,0 +1,28 @@ +--- +import { Image } from 'astro:assets' +import Networks from './Networks.astro' +import avatar from '@images/avatar.jpg' +import config from '@config/blog.config.ts' +import styles from './Vcard.module.css' + +const { author, rss, jsonfeed } = config +const { mastodon, twitter, github, name, url } = author +const links = [mastodon, github, twitter, rss, jsonfeed] +--- + +avatar + +

+ {config.siteDescription.replace(name, '')}{' '} + +

+ + diff --git a/src/components/molecules/Vcard.module.css b/src/components/Footer/Vcard.module.css similarity index 66% rename from src/components/molecules/Vcard.module.css rename to src/components/Footer/Vcard.module.css index 30ce8650..34be7194 100644 --- a/src/components/molecules/Vcard.module.css +++ b/src/components/Footer/Vcard.module.css @@ -1,8 +1,10 @@ .avatar { - composes: frame from '../atoms/Image.module.css'; + composes: frame from '@components/Picture/index.module.css'; border: 2px solid transparent; - border-radius: 50%; + border-radius: 50% !important; margin-bottom: calc(var(--spacer) / 3); + width: 80px; + height: 80px; } .description { diff --git a/src/components/Footer/index.astro b/src/components/Footer/index.astro new file mode 100644 index 00000000..e033c6ff --- /dev/null +++ b/src/components/Footer/index.astro @@ -0,0 +1,30 @@ +--- +import { Github, Bitcoin } from '@images/components' +import Vcard from './Vcard.astro' +import styles from './index.module.css' +import config from '@config/blog.config' + +const year = new Date().getFullYear() +const { name, url, github } = config.author +--- + + diff --git a/src/components/organisms/Footer.module.css b/src/components/Footer/index.module.css similarity index 100% rename from src/components/organisms/Footer.module.css rename to src/components/Footer/index.module.css diff --git a/src/components/Hamburger.astro b/src/components/Hamburger.astro new file mode 100644 index 00000000..2990b3ca --- /dev/null +++ b/src/components/Hamburger.astro @@ -0,0 +1,84 @@ +--- +const { props } = Astro +--- + + + + diff --git a/src/components/Header/index.astro b/src/components/Header/index.astro new file mode 100644 index 00000000..36989bad --- /dev/null +++ b/src/components/Header/index.astro @@ -0,0 +1,21 @@ +--- +import Menu from '@components/Menu/index.astro' +import Search from '@components/Search/index.astro' +import ThemeSwitch from '@components/ThemeSwitch/index.astro' +import { Logo } from '@images/components' +import styles from './index.module.css' +--- + +
+
+ + kremalicious + + + +
+
diff --git a/src/components/organisms/Header.module.css b/src/components/Header/index.module.css similarity index 96% rename from src/components/organisms/Header.module.css rename to src/components/Header/index.module.css index b7ce3f3c..42633b44 100644 --- a/src/components/organisms/Header.module.css +++ b/src/components/Header/index.module.css @@ -11,7 +11,7 @@ .headerContent { padding: 0 calc(var(--spacer) / 1.5); - max-width: var(--maxWidthContainer); + max-width: var(--maxWidthContent); margin-left: auto; margin-right: auto; position: relative; diff --git a/src/components/atoms/Input.module.css b/src/components/Input/index.module.css similarity index 93% rename from src/components/atoms/Input.module.css rename to src/components/Input/index.module.css index aa5cb779..3162105a 100644 --- a/src/components/atoms/Input.module.css +++ b/src/components/Input/index.module.css @@ -8,7 +8,7 @@ color: var(--input-color); background-color: var(--input-bg); background-image: none; - border: var(--stroke-width) solid transparent; + border: var(--border-width) solid var(--border-color); border-radius: var(--border-radius); box-shadow: none; transition: all ease-in-out 0.15s; diff --git a/src/components/Input/index.test.tsx b/src/components/Input/index.test.tsx new file mode 100644 index 00000000..95dfadd5 --- /dev/null +++ b/src/components/Input/index.test.tsx @@ -0,0 +1,8 @@ +import { render, screen } from '@testing-library/react' +import { test } from 'vitest' +import Input from '.' + +test('Input', async () => { + render() + await screen.findByRole('textbox') +}) diff --git a/src/components/atoms/Input.tsx b/src/components/Input/index.tsx similarity index 64% rename from src/components/atoms/Input.tsx rename to src/components/Input/index.tsx index 6504b585..5ac12543 100644 --- a/src/components/atoms/Input.tsx +++ b/src/components/Input/index.tsx @@ -1,5 +1,5 @@ -import React, { InputHTMLAttributes, ReactElement } from 'react' -import * as styles from './Input.module.css' +import { type InputHTMLAttributes, type ReactElement } from 'react' +import styles from './index.module.css' export default function Input({ className, diff --git a/src/components/Layout.test.tsx b/src/components/Layout.test.tsx deleted file mode 100644 index 2555b3c4..00000000 --- a/src/components/Layout.test.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react' -import testRender from '../../.jest/testRender' -import Layout from './Layout' - -describe('Layout', () => { - testRender(Hello) -}) diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx deleted file mode 100644 index 4ab07349..00000000 --- a/src/components/Layout.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React, { ReactElement } from 'react' -import * as styles from './Layout.module.css' -import Typekit from './atoms/Typekit' -import Footer from './organisms/Footer' -import Header from './organisms/Header' - -export default function Layout({ children }: { children: any }): ReactElement { - return ( - <> - -
- -
-
{children}
-
- -