diff --git a/bin/heimdall b/bin/heimdall new file mode 100755 index 00000000..82c0cc18 --- /dev/null +++ b/bin/heimdall @@ -0,0 +1,16 @@ +#!/bin/bash + + +docker run -d \ + --name=heimdall \ + -e PUID=1000 \ + -e PGID=1000 \ + -e TZ=Etc/UTC \ + -p 80:80 \ + -p 443:443 \ + -v heimdall:/config \ + -it --rm \ + lscr.io/linuxserver/heimdall:latest + + +# --restart unless-stopped \ \ No newline at end of file diff --git a/bin/links b/bin/links new file mode 100755 index 00000000..f074e7cd --- /dev/null +++ b/bin/links @@ -0,0 +1,53 @@ +#!/usr/bin/env ruby + +require 'date' +require 'fileutils' + +dir = "/Users/wschenk/Library/Mobile Documents/iCloud~md~obsidian/Documents/my awesome vault/links" + +# Create a hash to store files by week +files_by_week = {} + +# Loop through files in the directory +Dir.glob(File.join(dir, "*.md")).each do |file| + filename = File.basename(file, ".md") + puts filename + date = Date.parse(filename) rescue next # Skip if filename is not a valid date + + # Determine the week number + week = date.strftime("%Y-W%W") + + # Initialize array for this week if it doesn't exist + files_by_week[week] ||= [] + + # Add file to the appropriate week + files_by_week[week] << file +end + +# Process each week +files_by_week.each do |week, files| + output = "# Week #{week}\n\n" + + files.sort.each do |file| + filename = File.basename(file) + content = File.read(file) + + # Remove date and ".md" from filename + header = File.basename(filename, ".md").sub(/^\d{4}-\d{2}-\d{2}-/, '') + output += "## #{header}\n\n" + + # Add file contents + output += "#{content}\n\n" + end + + # Write output to file + output_dir = File.join(dir, "../weekly_summaries") + FileUtils.mkdir_p(output_dir) + output_file = File.join(output_dir, "#{week}.md") + File.write(output_file, output) + + # Print directory and filename + puts "Writing file: #{output_file}" +end + +puts "Output directory: #{File.join(dir, 'weekly_summaries')}" \ No newline at end of file diff --git a/content/articles/2024/coding_with_cursor/cover.png b/content/articles/2024/coding_with_cursor/cover.png new file mode 100644 index 00000000..ba35008c Binary files /dev/null and b/content/articles/2024/coding_with_cursor/cover.png differ diff --git a/content/articles/2024/coding_with_cursor/index.org b/content/articles/2024/coding_with_cursor/index.org new file mode 100644 index 00000000..d32f227a --- /dev/null +++ b/content/articles/2024/coding_with_cursor/index.org @@ -0,0 +1,45 @@ +#+title: Coding with cursor +#+date: 2024-09-20T16:02:46 +#+draft: true + +I want to build a static app using modern javascript and html that +that uses webcomponents. each component will live it its own file. +The task of the application is to manage assets, and it will use +supabase to do so. When a file is dragged onto the window, that gets +added to the upload queue. The user can also press space to record +audio, and space again to stop the recording and it will get added to +the upload queue. The user can also press a button which lets them do +a video recording, which when stopped will get added to the upload +queue. When something is added to the upload queue, or if the +device's network setting gets changes like they lost connectivity, +everything is first stored locally in the webbrowser as a PWA so that +the upload can resume. There's a process bar for the uploading so the +user can see which files have been sucessfully uploaded or not + + + +please contiue the implmentation + + +progress bar is referenced but not implemented + + + +can you import subapase from + + +wait until the window is ready event to initialize supabase + + + +{statusCode: '403', error: 'Unauthorized', message: 'new row violates row-level security policy'} + + +actually can you use supabase to get the anon user when it first starts up and print it out + + + +* References +# Local Variables: +# eval: (add-hook 'after-save-hook (lambda ()(org-babel-tangle)) nil t) +# End: diff --git a/content/howto/2024/astro_and_obsidian/cover.png b/content/howto/2024/astro_and_obsidian/cover.png new file mode 100644 index 00000000..5e515b23 Binary files /dev/null and b/content/howto/2024/astro_and_obsidian/cover.png differ diff --git a/content/howto/2024/astro_and_obsidian/index.org b/content/howto/2024/astro_and_obsidian/index.org new file mode 100644 index 00000000..07784e82 --- /dev/null +++ b/content/howto/2024/astro_and_obsidian/index.org @@ -0,0 +1,412 @@ +#+title: Astro and Obsidian +#+subtitle: easy editing +#+tags[]: obsidian astro +#+date: 2024-11-19T19:01:26 + +I like obsidian a lot as an editor, and I wanted to see if I could +use it to manage an astro site. Also, I've never built an astro site. + +Obsidian has a built in publishing feature, but I'm not sure that I +fully understand how it works. Specifically I don't like the links +between, the graph thing, and I'm not really sure how it thinks of how +the content is managed. It could be amazing -- I haven't really +looked at it. + +Anyway, lets figure it out. First you need node, then you need +obsidian. + +* Create the site and add tailwind + +#+begin_src bash + npm create astro@latest my-project +#+end_src + +Say blank, whatever you want to typescript, and install dependancies +and a git repo. + +Then =cd my-project= and + +#+begin_src bash + npx astro add tailwind + npm install -D @tailwindcss/typography +#+end_src + +And then make sure that you have the typography plugin installed in +=tailwind.config.mjs=: + +#+begin_src javascript + /** @type {import('tailwindcss').Config} */ + export default { + content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"], + theme: { + extend: {}, + }, + plugins: [require("@tailwindcss/typography")], + }; + +#+end_src + +* Create the BaseLayout + +And start up the dev server + +#+begin_src bash + npm run dev + +#+end_src + +Make a layout in =src/layouts/BaseLayout.astro=: + +#+begin_src html + --- + const pageTitle = Astro.props.title || "My Astro Blog"; + --- + + + + + + + {pageTitle} + + + + + + + +#+end_src + +You can test out if tailwind is working right by changing the content +of =src/pages/index.astro= and adding some tailwind classes, like + +#+begin_src html +--- +import BaseLayout from "../layout/BaseLayout.astro"; +--- + +

Astro

+

Here is a bunch of my text

+
+#+end_src + + +* Add =astro-rehype-relative-markdown-links= + +One of the fun things is to link between notes. Lets set that up so +astro understands obsidian links. First the astro side: + +#+begin_src bash + npm install astro-rehype-relative-markdown-links +#+end_src + +And so your =astro.config.mjs= looks like: + +#+begin_src js + import { defineConfig } from "astro/config"; + + import tailwind from "@astrojs/tailwind"; + import rehypeAstroRelativeMarkdownLinks from "astro-rehype-relative-markdown-links"; + + // https://astro.build/config + export default defineConfig({ + integrations: [tailwind()], + markdown: { + rehypePlugins: [rehypeAstroRelativeMarkdownLinks], + }, + }); +#+end_src + +Now on the Obsidian side, go to =Manage Vaults= and then create a new vault. + +Call the vault =posts= and put it the =my-project/src/content= directory. + +In preferences, under =Files and Links=, turn off "wikilinks". + +* Make the post page templates + +Then create =src/pages/posts/[...slug].astro=: + +First we define =getStaticPaths=, which returns a list of pages that we +want to render. The =slug= is the name of the url (basically) and =entry= +is the post itself. This is what tell astro that these urls exist and +need to be rendered. + +Then in the html part, we put the title, date, and a list of tags that +may or may not be defined. + +#+begin_src html + --- + import BaseLayout from "../../layout/BaseLayout.astro"; + import { getCollection } from 'astro:content'; + import type { CollectionEntry } from 'astro:content'; + + // 1. Generate a new path for every collection entry + export async function getStaticPaths() { + const blogEntries = await getCollection('posts'); + return blogEntries.map(entry => ({ + params: { slug: entry.slug }, props: { entry }, + })); + } + // 2. For your template, you can get the entry directly from the prop + + const { entry } = Astro.props; + type Props = { + entry: CollectionEntry<'posts'>; + }; + const { Content } = await entry.render(); + --- + +

{entry.data.title}

+

{entry.data.date}

+

Tags

+ +
+ +
+
+#+end_src + +If you run the dev server, and don't have the BaseLayout specify the right +charset you might see smart quotes all funky. + +#+begin_src html + +#+end_src + +So make that that is in the header (which probably should be there +anyway.) + + +* Create a few pages + +Back in obsidian, lets create some pages. In the Welcome page, remove +everything and then create a new link to a new page. + +You can drag images into Obsidian and they will get optimized and +deployed as needed. + +* Add support for callouts + +#+begin_src bash + npm install remark-obsidian-callout --save-dev + +#+end_src + +And inside of =astro.config.mjs=: + +#+begin_src javascript +import { defineConfig } from "astro/config"; + +import tailwind from "@astrojs/tailwind"; +import rehypeAstroRelativeMarkdownLinks from "astro-rehype-relative-markdown-links"; +import remarkObsidianCallout from "remark-obsidian-callout"; + +// https://astro.build/config +export default defineConfig({ + integrations: [tailwind()], + markdown: { + rehypePlugins: [rehypeAstroRelativeMarkdownLinks], + remarkPlugins: [remarkObsidianCallout], + }, +}); +#+end_src + +/Adjust your blockquote styles as needed/. + + +* Create a template for a post + +Create a =templates= folder and create =post.md= inside. + +#+begin_src markdown +--- +title: +date: {{date}} +tags: +--- + +#+end_src + +Inside of your obsidian settings select =templates= as the template +folder. + +* Create a blog index + +Get all the posts from the post collection, and sort them by date. + +=src/pages/blog.astro=: + +#+begin_src html + --- + import BaseLayout from "../layout/BaseLayout.astro"; + import { getCollection } from 'astro:content'; + + const allPosts = await getCollection('posts'); + // Sort posts by date + allPosts.sort((a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime()); + + --- + +

Posts

+ +
+ + +#+end_src + +This links to the =posts/= pages that we defined above. + +* Tags + +How about tags? + +First lets create =src/pages/tags.astro= to display the list of tags. + +We get all of the posts, then all of the tags in each post and add +them to a map of arrays. We could list out each post here, or just show +the count of posts with that specific date. + +#+begin_src html + --- + import { getCollection } from 'astro:content'; + import BaseLayout from "../layout/BaseLayout.astro"; + const allPosts = await getCollection('posts'); + + const tags = {}; + + allPosts.forEach((post) => { + post.data.tags?.forEach((tag) => { + tags[tag] = tags[tag] || []; + tags[tag].push(post); + }); + }); + + --- + +

Tags

+ + +
+ +#+end_src + +And then we can create =src/pages/tags/[...slug].astro= to render each of the tag pages: + +#+begin_src html + --- + import { getCollection } from 'astro:content'; + import BaseLayout from "../../layout/BaseLayout.astro"; + + // 1. Generate a new path for every collection entry + export async function getStaticPaths() { + const allPosts = await getCollection('posts'); + const uniqueTags = [...new Set(allPosts.flatMap(post => post.data.tags ?? []))]; + + return uniqueTags.map(tag => ({ + params: { slug: tag }, + props: { + tag, + posts: allPosts.filter(post => post.data.tags?.includes(tag)) + } + })); + } + + // 2. For your template, you can get the entry directly from the prop + const { tag,posts } = Astro.props; + --- + +

{tag}

+ +
+#+end_src + + +* RSS + +First lets add the package: + +#+begin_src bash +npm install @astrojs/rss +#+end_src + + +=src/utils/posts.js=: + +#+begin_src javascript +import { getCollection } from "astro:content"; + +export async function getPosts() { + let posts = await getCollection("posts"); + // Sort posts by date + posts.sort( + (a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime() + ); + + // Filter out posts without a date or where date is not a real date + posts = posts.filter( + (post) => post.data.date && !isNaN(new Date(post.data.date).getTime()) + ); + + return posts; +} +#+end_src + +And then create =src/pages/rss.xml.js=: + +#+begin_src javascript + import rss from "@astrojs/rss"; + import { getPosts } from "../utils/posts"; + + export async function GET(context) { + const posts = await getPosts(); + + posts.forEach((post) => { + console.log("title", post.data.title || post.slug); + console.log("date", post.data.date); + console.log( + "description", + post.data.description || post.data.title || post.slug + ); + console.log("link", `/posts/${post.slug}`); + console.log("---"); + }); + + // console.log(blog); + return rss({ + title: "Obsidian Blog", + description: "Rocks are cool", + site: context.site || "https://obsidian.blog", + items: posts.map((post) => ({ + title: post.data.title || post.slug, + pubDate: post.data.date, + description: post.data.description || post.data.title || post.slug, + // Compute RSS link from post `slug` + link: `/posts/${post.slug}`, + })), + }); + } +#+end_src + + + +* References + +1. https://stackoverflow.com/questions/76163067/using-markdown-wiki-links-in-astro-framework +1. https://github.com/vernak2539/astro-rehype-relative-markdown-links +1. https://www.npmjs.com/package/remark-obsidian-callout +2. https://help.obsidian.md/Editing+and+formatting/Callouts +3. https://docs.astro.build/en/guides/rss/ + + +# Local Variables: +# eval: (add-hook 'after-save-hook (lambda ()(org-babel-tangle)) nil t) +# End: diff --git a/content/howto/2024/coding_with_ai/cover.png b/content/howto/2024/coding_with_ai/cover.png new file mode 100644 index 00000000..ceb4ef44 Binary files /dev/null and b/content/howto/2024/coding_with_ai/cover.png differ diff --git a/content/howto/2024/coding_with_ai/index.org b/content/howto/2024/coding_with_ai/index.org new file mode 100644 index 00000000..f40991a3 --- /dev/null +++ b/content/howto/2024/coding_with_ai/index.org @@ -0,0 +1,216 @@ +#+title: Coding with AI +#+subtitle: v0 and cursor +#+tags[]: nextjs v0 cursor +#+date: 2024-09-13T10:21:38 +#+draft: true + +* v0 + +Head over to v0.chat dev, and lets give it a prompt: + +#+begin_quote +Make a UI that is to help people plan road trips. It will search and +show you where electric vehicle chargers are and when you look at a +charger it will show you the things that are nearby it +#+end_quote + +Click add to codebase on the top right, and copy it to the clipboard. + +In my case + +#+begin_src bash + npx shadcn@latest add "https://v0.dev/chat/b/2hbXmv8?token=eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..I0FAEsakOaAJzb39.gDmpasvmglij1M-9qv8S9W22x2ySMS2F1G5mZS-TObk9_p-6GqE.8abpyK0OchsJ3jMu_53r-A" +#+end_src + +* Setup the nextjs app + +#+begin_src bash + cd $(mktemp -d) + npx create-next-app@latest + +#+end_src + +I named it =roadtrip= and accepted all of the defaults. + +#+begin_src bash + cd roadtrip + cursor roadtrip + #+end_src + +* Add our page + +Run the =shadcn= command above + +#+begin_src bash +✔ You need to create a component.json file to add components. Proceed? … yes +✔ Which style would you like to use? › New York +✔ Which color would you like to use as the base color? › Zinc +✔ Would you like to use CSS variables for theming? … no / yes +✔ Writing components.json. +✔ Checking registry. +✔ Installing dependencies. +✔ Created 6 files: + - components/road-trip-planner.tsx + - components/ui/button.tsx + - components/ui/input.tsx + - components/ui/card.tsx + - components/ui/tabs.tsx + - components/ui/scroll-area.tsx +#+end_src + +Then replace =app/page.tsx= with + +#+begin_src typescript + import { RoadTripPlannerComponent } from "@/components/road-trip-planner"; + + export default function Home() { + return ; + } +#+end_src + +Run =npm run dev= to start up the server and check out +[[http://localhost:3000]] + +* Comsposer + +command i to start the composer + +add the mapbox docs by typeing @docs and then putting in [[https://docs.mapbox.com/]] + +add openrouting serving by typing @docs and then adding https://openrouteservice.org/dev/ + +add road-trip-planner to the composer + +#+begin_quote +with @Mapboxfactor our the place holder of the map to use mapbox. +when its first loaded the map will be centered around where the user +is, and when map is dragged around it will do a search to the backend +to see which chargers are available. If the user enters in location, +it will first look to see where the @OpenRouteService drive is and +plot that on the map, giving a list of chargers that are nearby +#+end_quote + +then i say + +#+begin_quote +put that component in a seperate file +#+end_quote + +Accept all the changes. + +Add the library it asks + +#+begin_src bash + npm install mapbox-gl @types/mapbox-gl +#+end_src + +Sign up for a mapbox account + +Get an access token, and then =.env.local= file with the token in it. +Add to =.gitignore= and make sure that the =MapComponent= is using it. + +(Select it, command-k, and say "pull the token from the environment file") + +Looks like the refactoring didn't work totally, just select everything +in =road-trip-planner= and say that the map stuff should be in the +subcomponent. + +* Add route look up + +Clear out the composer, and open up the road-trip-planner pane + +#+begin_quote +for the location planner, use @OpenRouteService to lookup a list of +matching city names. Once the user selects them, put a pin on the map +to the destination and look up the route to drive from one place to +the other +#+end_quote + +Go to openrouteservice.org + +Create an account and create a key + +Update =OPENROUTE_API_KEY= in =.env.local= + +Test it out, and it doesn't work. Looking at the web console I see an error + +#+begin_quote +Instead of having to press the button to search, can you have it start +searching while I'm typing. Also, it says GET +http://localhost:3000/api/geocode?query=burtlington 404 (Not Found) +#+end_quote + +Apply the changes, add the new library + +#+begin_src bash + npm install use-debounce +#+end_src + +and restart + +* Tweaks + +#+begin_quote +show the label part in the city selector +#+end_quote + +#+begin_quote +do to the trip planning itself, a curl call to get the results looks +like this + +curl -X POST \ + 'https://api.openrouteservice.org/v2/directions/driving-car' \ + -H 'Content-Type: application/json; charset=utf-8' \ + -H 'Accept: application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8' \ + -H 'Authorization: 5b3ce3597851110001cf624896eaf204218948f19f0b26277e6b19ba' \ + -d '{"coordinates":[[8.681495,49.41461],[8.686507,49.41943],[8.687872,49.420318]]}'. the results look like this curl -X POST \ + 'https://api.openrouteservice.org/v2/directions/driving-car' \ + -H 'Content-Type: application/json; charset=utf-8' \ + -H 'Accept: application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8' \ + -H 'Authorization: 5b3ce3597851110001cf624896eaf204218948f19f0b26277e6b19ba' \ + -d '{"coordinates":[[8.681495,49.41461],[8.686507,49.41943],[8.687872,49.420318]]}' +#+end_quote + +* Add chargers to the map + + +#+begin_quote +ok, now i want to search for chargers that are around the polyline, +and pin them on the map. Update the list on the left to show which +chargers are available. Use the end point +@https://chargermap.fly.dev/in_map?n=44.600735057768574&e=-72.87918090820314&s=44.36804189293885&w=-73.72238159179689&connectors=null&dc=true&level1=true&level2=true +which is the box that it will return the chargers in, and the three +different types of chargers. level1, level2 and dc fast chargers. +show a different pin for each of the chargers. an example of the json +it returns is { + + + "id": 32973, + "latitude": 44.469281, + "longitude": -73.154972, + "name": "Burlington International Airport", + "address": "1200 Airport Dr", + "city": "South Burlington", + "state": "VT", + "zip": "05403", + "country": "US", + "facility": "AIRPORT", + "level1": null, + "level2": 6, + "dcfast": null, + "network": "Non-Networked", + "date_last_confirmed": "2023-09-14", + "workplace": "true", + "chademo": null, + "j1772": 1, + "j1772combo": null, + "nema1450": null, + "nema515": null, + "tesla": null + }, +#+end_quote +* References +# Local Variables: +# eval: (add-hook 'after-save-hook (lambda ()(org-babel-tangle)) nil t) +# End: + diff --git a/content/howto/2024/manual_prerender_with_webcomponents/cover.png b/content/howto/2024/manual_prerender_with_webcomponents/cover.png new file mode 100644 index 00000000..5160e81d Binary files /dev/null and b/content/howto/2024/manual_prerender_with_webcomponents/cover.png differ diff --git a/content/howto/2024/manual_prerender_with_webcomponents/index.org b/content/howto/2024/manual_prerender_with_webcomponents/index.org new file mode 100644 index 00000000..f606b471 --- /dev/null +++ b/content/howto/2024/manual_prerender_with_webcomponents/index.org @@ -0,0 +1,24 @@ +#+title: Manual prerender with webcomponents +#+date: 2024-09-09T17:23:18 +#+draft: true + +This works better when you use the regular not shadow dom! + +#+begin_src typescript + import puppeteer from "https://deno.land/x/puppeteer@16.2.0/mod.ts"; + + const browser = await puppeteer.launch(); + const page = await browser.newPage(); + await page.goto("http://127.0.0.1:8000", { + waitUntil: "networkidle2", + }); + + const html = await page.content(); // serialized HTML of page DOM. + console.log(html); + await page.screenshot({ path: "example.png" }); + await browser.close(); +#+end_src +* References +# Local Variables: +# eval: (add-hook 'after-save-hook (lambda ()(org-babel-tangle)) nil t) +# End: diff --git a/content/howto/2024/using_shadcn_and_magicui/cover.png b/content/howto/2024/using_shadcn_and_magicui/cover.png new file mode 100644 index 00000000..62d2e3ab Binary files /dev/null and b/content/howto/2024/using_shadcn_and_magicui/cover.png differ diff --git a/content/howto/2024/using_shadcn_and_magicui/index.org b/content/howto/2024/using_shadcn_and_magicui/index.org new file mode 100644 index 00000000..51043a6f --- /dev/null +++ b/content/howto/2024/using_shadcn_and_magicui/index.org @@ -0,0 +1,93 @@ +#+title: Using shadcn and magicui +#+subtitle: all the cool kids are doing it +#+tags[]: shadcd magicui +#+date: 2024-09-10T14:17:20 +#+draft: true + +I've never used [[https://ui.shadcn.com/][shadcn]] or [[https://magicui.design/][magicui]] so lets play! +at once! + +* Create a new directory and a nextapp + +#+begin_src bash + cd $(mktemp -d) + + + ✔ What is your project named? … monkeythumb +✔ Would you like to use TypeScript? … No / Yes +✔ Would you like to use ESLint? … No / Yes +✔ Would you like to use Tailwind CSS? … No / Yes +✔ Would you like to use `src/` directory? … No / Yes +✔ Would you like to use App Router? (recommended) … No / Yes +✔ Would you like to customize the default import alias (@/*)? … No / Yes +#+end_src + +The open it up +* shadcn install + +#+begin_src bash + pnpm dlx shadcn@latest init -d +#+end_src + +* Add that button + +#+begin_src bash + pnpm dlx shadcn@latest add button +#+end_src + + +#+begin_src typescript + // app/page.tsx + import { Button } from "@/components/ui/button"; + + export default function Home() { + return ; + } + + +#+end_src + +* Install magicui + +#+begin_src bash + pnpm dlx magicui-cli init + + +#+end_src + +* Try the globe + +#+begin_src bash +pnpm dlx magicui-cli add globe + +#+end_src + +And copy intoe =app.page.tsx= + +#+begin_src typescript +import Globe from "@/components/magicui/globe"; + +export default function Home() { + return ( +
+ + Globe + + +
+
+ ); +} + +#+end_src + +* Build a landing page + +#+begin_src bash +pnpm dlx magicui-cli add typing-animation + +#+end_src +* References +# Local Variables: +# eval: (add-hook 'after-save-hook (lambda ()(org-babel-tangle)) nil t) +# End: diff --git a/content/howto/2024/website_to_markdown/cover.png b/content/howto/2024/website_to_markdown/cover.png new file mode 100644 index 00000000..76309ada Binary files /dev/null and b/content/howto/2024/website_to_markdown/cover.png differ diff --git a/content/howto/2024/website_to_markdown/index.org b/content/howto/2024/website_to_markdown/index.org new file mode 100644 index 00000000..29499173 --- /dev/null +++ b/content/howto/2024/website_to_markdown/index.org @@ -0,0 +1,47 @@ +#+title: Website to markdown +#+date: 2024-11-12T10:48:47 +#+draft: true + + +* Installation + +#+begin_src bash + brew install JohannesKaufmann/tap/html2markdown +#+end_src + +or + +#+begin_src bash + go install github.com/JohannesKaufmann/html-to-markdown/v2/cli@latest + + # rename + (cd $(go env GOBIN); mv cli html2markdown) +#+end_src + +* Running + +Examples: + +#+begin_src bash :results output + curl --no-progress-meter https://willschenk.com/fragments/2024/four_freedoms/ | html2markdown +#+end_src + +#+begin_src bash :results output + curl --no-progress-meter https://www.nytimes.com/2024/11/12/world/europe/amanda-knox-perugia-italy.html | html2markdown +#+end_src + + +#+begin_src bash :results output + curl --no-progress-meter https://html-to-markdown.com/ | html2markdown +#+end_src + + + + +* References + +1. https://github.com/JohannesKaufmann/html-to-markdown + +# Local Variables: +# eval: (add-hook 'after-save-hook (lambda ()(org-babel-tangle)) nil t) +# End: diff --git a/content/labnotes/2024/adding_obsidian_clipper/cover.png b/content/labnotes/2024/adding_obsidian_clipper/cover.png new file mode 100644 index 00000000..72f8bb87 Binary files /dev/null and b/content/labnotes/2024/adding_obsidian_clipper/cover.png differ diff --git a/content/labnotes/2024/adding_obsidian_clipper/index.org b/content/labnotes/2024/adding_obsidian_clipper/index.org new file mode 100644 index 00000000..2137fa18 --- /dev/null +++ b/content/labnotes/2024/adding_obsidian_clipper/index.org @@ -0,0 +1,34 @@ +#+title: Adding obsidian clipper +#+subtitle: organizing and collecting +#+tags[]: obsidian +#+date: 2024-09-26T15:57:10 +#+draft: true + +Install the [[https://chromewebstore.google.com/detail/obsidian-clipper/mphkdfmipddgfobjhphabphmpdckgfhb][extention from the chrome web store]]. + +Select you vault name, like: + +=my awesome vault= + +I like to put things into a link directory, so we create a new note +with the template of =links/{date}-{title}= + +#+begin_src markdown + > {clip} + +- [{title}]({url}) on [[Daily/{date}]]. [[{year}/{month}]]. +#+end_src + +Then pin the extention. + +* If it flashes + +Open up the extension settings and test the configuration -- then +check the "always" checkbox. + + + +* References +# Local Variables: +# eval: (add-hook 'after-save-hook (lambda ()(org-babel-tangle)) nil t) +# End: diff --git a/content/labnotes/2024/compressing_images_for_web/cover.png b/content/labnotes/2024/compressing_images_for_web/cover.png new file mode 100644 index 00000000..3f2f0c80 Binary files /dev/null and b/content/labnotes/2024/compressing_images_for_web/cover.png differ diff --git a/content/labnotes/2024/compressing_images_for_web/index.org b/content/labnotes/2024/compressing_images_for_web/index.org new file mode 100644 index 00000000..f7da824a --- /dev/null +++ b/content/labnotes/2024/compressing_images_for_web/index.org @@ -0,0 +1,99 @@ +#+title: Compressing images for web +#+subtitle: just smoosh them +#+tags[]: node javascript sharp +#+date: 2024-11-04T13:25:04 +#+draft: true + +#+begin_src bash + npm i -D sharp +#+end_src + +Then, assuming your source images in the =src/images= directory: + +#+begin_src javascript + const sharp = require("sharp"); + const fs = require("fs"); + const path = require("path"); + + const imagesDir = path.join(__dirname, "src", "images"); + + // Read all files in the images directory + fs.readdir(imagesDir, (err, files) => { + if (err) { + console.error("Error reading images directory:", err); + return; + } + + // Process each image file + files.forEach((file) => { + // Skip files that already end with _small.jpg + if (file.endsWith("_small.jpg")) { + return; + } + + console.log(`Processing ${file}`); + + const inputPath = path.join(imagesDir, file); + + // Generate output filename by inserting _small before extension + const parsedFile = path.parse(file); + const outputFile = `${parsedFile.name}_small.jpg`; + const outputPath = path.join(imagesDir, outputFile); + + // Compress and convert to jpg + sharp(inputPath) + .jpeg({ + quality: 80, // Adjust quality (0-100) + chromaSubsampling: "4:4:4", + }) + .resize(1920, 1080, { + fit: "inside", // Maintain aspect ratio + withoutEnlargement: true, // Don't enlarge smaller images + }) + .toFile(outputPath) + .then(() => { + console.log(`Compressed ${file} -> ${outputFile}`); + }) + .catch((err) => { + console.error(`Error processing ${file}:`, err); + }); + }); + }); + + +#+end_src + + +Which really gets things down: + +#+begin_src bash + node compress.js +Processing image1.png +Processing image2.png +Processing image3.png +Processing image4.png +Compressed image3.png -> image3_small.jpg +Compressed image1.png -> image1_small.jpg +Compressed image2.png -> image2_small.jpg +Compressed image4.png -> image4_small.jpg +wschenk@Wills-MacBook-Pro thefocus-landing % ls -l src/images +total 27936 +-rw-r--r--@ 1 wschenk staff 2900871 Oct 23 16:27 image1.png +-rw-r--r--@ 1 wschenk staff 355771 Nov 4 13:34 image1_small.jpg +-rw-r--r--@ 1 wschenk staff 3215392 Oct 23 16:27 image2.png +-rw-r--r--@ 1 wschenk staff 387309 Nov 4 13:34 image2_small.jpg +-rw-r--r--@ 1 wschenk staff 1864875 Oct 23 16:28 image3.png +-rw-r--r--@ 1 wschenk staff 252299 Nov 4 13:34 image3_small.jpg +-rw-r--r--@ 1 wschenk staff 5263239 Oct 23 16:28 image4.png +-rw-r--r--@ 1 wschenk staff 45470 Nov 4 13:34 image4_small.jpg + +#+end_src + + +* References + +1. https://sharp.pixelplumbing.com/install#prebuilt-binaries + +# Local Variables: +# eval: (add-hook 'after-save-hook (lambda ()(org-babel-tangle)) nil t) +# End: diff --git a/content/labnotes/2024/reading_feeds_with_fresh_rss/cover.png b/content/labnotes/2024/reading_feeds_with_fresh_rss/cover.png new file mode 100644 index 00000000..4977bc00 Binary files /dev/null and b/content/labnotes/2024/reading_feeds_with_fresh_rss/cover.png differ diff --git a/content/labnotes/2024/reading_feeds_with_fresh_rss/index.org b/content/labnotes/2024/reading_feeds_with_fresh_rss/index.org new file mode 100644 index 00000000..e2dbcbe6 --- /dev/null +++ b/content/labnotes/2024/reading_feeds_with_fresh_rss/index.org @@ -0,0 +1,23 @@ +#+title: Reading feeds with FreshRSS +#+date: 2024-09-22T20:04:33 +#+draft: true + +#+begin_src bash + docker run -it --rm \ + --log-opt max-size=10m \ + -p 8080:80 \ + -e TZ=Europe/Paris \ + -e 'CRON_MIN=1,31' \ + -v freshrss_data:/var/www/FreshRSS/data \ + -v freshrss_extensions:/var/www/FreshRSS/extensions \ + --name freshrss \ + freshrss/freshrss + +#+end_src + + + +* References +# Local Variables: +# eval: (add-hook 'after-save-hook (lambda ()(org-babel-tangle)) nil t) +# End: