Laser stand
This commit is contained in:
BIN
src/assets/images/laser-stand/assembled.jpg
Normal file
BIN
src/assets/images/laser-stand/assembled.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 MiB |
BIN
src/assets/images/laser-stand/close.jpg
Normal file
BIN
src/assets/images/laser-stand/close.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 MiB |
BIN
src/assets/images/laser-stand/design.png
Normal file
BIN
src/assets/images/laser-stand/design.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
@@ -1,66 +0,0 @@
|
|||||||
---
|
|
||||||
import LinkButton from "./LinkButton.astro";
|
|
||||||
import socialIcons from "@assets/socialIcons";
|
|
||||||
|
|
||||||
const URL = Astro.url;
|
|
||||||
|
|
||||||
const shareLinks = [
|
|
||||||
{
|
|
||||||
name: "WhatsApp",
|
|
||||||
href: "https://wa.me/?text=",
|
|
||||||
linkTitle: `Share this post via WhatsApp`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Facebook",
|
|
||||||
href: "https://www.facebook.com/sharer.php?u=",
|
|
||||||
linkTitle: `Share this post on Facebook`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "X",
|
|
||||||
href: "https://x.com/intent/post?url=",
|
|
||||||
linkTitle: `Share this post on X`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Telegram",
|
|
||||||
href: "https://t.me/share/url?url=",
|
|
||||||
linkTitle: `Share this post via Telegram`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Pinterest",
|
|
||||||
href: "https://pinterest.com/pin/create/button/?url=",
|
|
||||||
linkTitle: `Share this post on Pinterest`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Mail",
|
|
||||||
href: "mailto:?subject=See%20this%20post&body=",
|
|
||||||
linkTitle: `Share this post via email`,
|
|
||||||
},
|
|
||||||
] as const;
|
|
||||||
---
|
|
||||||
|
|
||||||
<div class={`social-icons`}>
|
|
||||||
<span class="italic">Share this post on:</span>
|
|
||||||
<div class="text-center">
|
|
||||||
{
|
|
||||||
shareLinks.map(social => (
|
|
||||||
<LinkButton
|
|
||||||
href={`${social.href + URL}`}
|
|
||||||
className="link-button"
|
|
||||||
title={social.linkTitle}
|
|
||||||
>
|
|
||||||
<Fragment set:html={socialIcons[social.name]} />
|
|
||||||
<span class="sr-only">{social.linkTitle}</span>
|
|
||||||
</LinkButton>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.social-icons {
|
|
||||||
@apply flex flex-col flex-wrap items-center justify-center gap-1 sm:items-start;
|
|
||||||
}
|
|
||||||
.link-button {
|
|
||||||
@apply scale-90 p-2 hover:rotate-6 sm:p-1;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
34
src/content/blog/laser-stand.md
Normal file
34
src/content/blog/laser-stand.md
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
pubDatetime: 2025-01-17T00:00:00Z
|
||||||
|
title: Laser stand 3d print
|
||||||
|
draft: false
|
||||||
|
tags:
|
||||||
|
- 3d-print
|
||||||
|
description: First 3d print of 2025
|
||||||
|
---
|
||||||
|
|
||||||
|
I've had a 3d printer for a fair few years now. It's a Prusa mk3 and it's starting to show it's age. I might consider a replacement in the next year or so - the Bambu Labs printers are looking pretty good.
|
||||||
|
|
||||||
|
Anyway, before I replace it I need to prove to myself that I'll use it.
|
||||||
|
|
||||||
|
This is a print that I've been wanting to do for a while. I bought a cheap Magnusson laser level a while back (it was around 40% of the cost of others I could find) and it's really good for drawing level lines, but what it lacks is a convenient way of placing it at just the right level.
|
||||||
|
|
||||||
|
We suffered for quite a while with balancing the level on stacks of random objects - not the best.
|
||||||
|
|
||||||
|
Later on I found a cheap camera tripod in a local charity shop. Now I just needed a way of connecting them together...
|
||||||
|
|
||||||
|
3d printer to the rescue
|
||||||
|
|
||||||
|
I fired up Fusion and designed a little plate to interface between the quick-release that the tripod has, and the 1/4-20 thread that the laser has.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
A quick print later and it's ready to go!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The (laser)disc is to enable me to point the laser in different directions without moving the tripod. Without it the laser doesn't line up with the quick-release, and this was apparently unacceptable to myself.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Functional prints are the best!
|
||||||
@@ -6,7 +6,6 @@ import Tag from "@components/Tag.astro";
|
|||||||
import Datetime from "@components/Datetime";
|
import Datetime from "@components/Datetime";
|
||||||
import type { CollectionEntry } from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import { slugifyStr } from "@utils/slugify";
|
import { slugifyStr } from "@utils/slugify";
|
||||||
import ShareLinks from "@components/ShareLinks.astro";
|
|
||||||
import { SITE } from "@config";
|
import { SITE } from "@config";
|
||||||
import {render} from 'astro:content'
|
import {render} from 'astro:content'
|
||||||
|
|
||||||
@@ -92,7 +91,7 @@ const nextPost =
|
|||||||
</article>
|
</article>
|
||||||
|
|
||||||
<ul class="my-8">
|
<ul class="my-8">
|
||||||
{tags.map(tag => <Tag tag={slugifyStr(tag)} />)}
|
{tags.map(tag => <Tag tag={tag} />)}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -110,7 +109,6 @@ const nextPost =
|
|||||||
<span>Back to Top</span>
|
<span>Back to Top</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<ShareLinks />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class="my-6 border-dashed" />
|
<hr class="my-6 border-dashed" />
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ const { page } = Astro.props;
|
|||||||
<Main pageTitle="Posts" pageDesc="All the articles I've posted.">
|
<Main pageTitle="Posts" pageDesc="All the articles I've posted.">
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
page.data.map(({ data, slug }) => (
|
page.data.map(({ data, id }) => (
|
||||||
<Card href={`/posts/${slug}/`} frontmatter={data} />
|
<Card href={`/posts/${id}/`} frontmatter={data} />
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ const { page, tag, tagName } = Astro.props;
|
|||||||
<h1 slot="title" transition:name={tag}>{`Tag:${tag}`}</h1>
|
<h1 slot="title" transition:name={tag}>{`Tag:${tag}`}</h1>
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
page.data.map(({ data, slug }) => (
|
page.data.map(({ data, id }) => (
|
||||||
<Card href={`/posts/${slug}/`} frontmatter={data} />
|
<Card href={`/posts/${id}/`} frontmatter={data} />
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
import type { CollectionEntry } from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import getSortedPosts from "./getSortedPosts";
|
import getSortedPosts from "./getSortedPosts";
|
||||||
import { slugifyAll } from "./slugify";
|
|
||||||
|
|
||||||
const getPostsByTag = (posts: CollectionEntry<"blog">[], tag: string) =>
|
const getPostsByTag = (posts: CollectionEntry<"blog">[], tag: string) =>
|
||||||
getSortedPosts(
|
getSortedPosts(posts.filter(post => post.data.tags.includes(tag)));
|
||||||
posts.filter(post => slugifyAll(post.data.tags).includes(tag))
|
|
||||||
);
|
|
||||||
|
|
||||||
export default getPostsByTag;
|
export default getPostsByTag;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const getUniqueTags = (posts: CollectionEntry<"blog">[]) => {
|
|||||||
const tags: Tag[] = posts
|
const tags: Tag[] = posts
|
||||||
.filter(postFilter)
|
.filter(postFilter)
|
||||||
.flatMap(post => post.data.tags)
|
.flatMap(post => post.data.tags)
|
||||||
.map(tag => ({ tag: slugifyStr(tag), tagName: tag }))
|
.map(tag => ({ tag: tag, tagName: tag }))
|
||||||
.filter(
|
.filter(
|
||||||
(value, index, self) =>
|
(value, index, self) =>
|
||||||
self.findIndex(tag => tag.tag === value.tag) === index
|
self.findIndex(tag => tag.tag === value.tag) === index
|
||||||
|
|||||||
Reference in New Issue
Block a user