team picohttps://hey.prose.sh2022-06-29T00:10:17Zofficial blog for pico.sh servicesheyaliases now supported for posts2023-03-15T19:54:02Zhttps://hey.prose.sh/aliases<p>Hey!</p>
<p>It's been awhile since we've posted on the official blog. I wanted to let
everyone know that we are still actively working on pico services and just
recently deployed a feature that I've been wanting for awhile: aliases.</p>
<p>This was one of the features that I needed in order to move my
<a href="https://erock.io" rel="nofollow">Hugo blog</a> to <a href="https://prose.sh" rel="nofollow">prose.sh</a>.</p>
<pre><code>---
title: My post
aliases:
- /some-other/url/very-nice.html
---
</code></pre>
<p>This feature in particular enables people to migrate blogs to prose.</p>
<p>As you'll see, <a href="https://erock.io" rel="nofollow">erock.io</a> has moved to prose successfully.</p>
<hr/>
<p>Join our <a href="https://pico.sh/irc" rel="nofollow">irc <span class="hashtag">#pico</span>.sh on libera</a> or email us at
<a href="mailto:~erock/pico.sh@lists.sr.ht" rel="nofollow">~erock/pico.sh@lists.sr.ht</a>.</p>
<p>Be sure to subscribe to our <a href="/rss" rel="nofollow">rss feed</a> to get the latest updates at team
pico.</p>
New blog layout2022-08-28T01:20:02Zhttps://hey.prose.sh/blog-layouts<p>We added the ability to customize your blog index layout.</p>
<p>The first layout that we are releasing is the "aside" layout. It was heavily
inspired by <a href="https://drewdevault.com" rel="nofollow">Drew DeVault's blog</a>.</p>
<p><a href="https://erock.prose.sh" rel="nofollow"><img src="/aside-layout.png" alt="example aside layout"></a></p>
<p>Changing your blog index to this layout is easy. All you have to do is edit your
<code>_readme.md</code> to add a <code>layout</code> frontmatter. Setting it to <code>aside</code> will apply the
new layout template.</p>
<pre class="chroma"><code><span class="line"><span class="ln">1</span><span class="cl">---
</span></span><span class="line"><span class="ln">2</span><span class="cl">layout: aside
</span></span><span class="line"><span class="ln">3</span><span class="cl">---
</span></span></code></pre><p>I'd also like to announce that I would be more than happy to apply patches for
more layouts. I'd also be happy to collaborate on them with anyone who is
interested.</p>
<p>Send all patches and collab requests to
<a href="mailto:~erock/pico.sh@lists.sr.ht" rel="nofollow">our mailing list</a>.</p>
<hr/>
<p>Join our <a href="https://pico.sh/irc" rel="nofollow">irc <span class="hashtag">#pico</span>.sh on libera</a> or email us at
<a href="mailto:~erock/pico.sh@lists.sr.ht" rel="nofollow">~erock/pico.sh@lists.sr.ht</a>.</p>
<p>Be sure to subscribe to our <a href="/rss" rel="nofollow">rss feed</a> to get the latest updates at team
pico.</p>
Experimenting with new layoutsAdd tags to your posts!2022-08-02T15:54:08Zhttps://hey.prose.sh/tag-support<p>We just launched a new feature for both <a href="https://prose.sh" rel="nofollow">prose.sh</a> and
<a href="https://lists.sh" rel="nofollow">lists.sh</a> that allows bloggers to add tags to their posts.</p>
<h2 id="prosesh"><a class="anchor" href="#prosesh" rel="nofollow">#</a> prose.sh</h2>
<pre class="chroma"><code><span class="line"><span class="ln">1</span><span class="cl">---
</span></span><span class="line"><span class="ln">2</span><span class="cl">title: Tag support launched
</span></span><span class="line"><span class="ln">3</span><span class="cl">description: writers can now tag posts for prose and lists
</span></span><span class="line"><span class="ln">4</span><span class="cl">date: 2022-08-02
</span></span><span class="line"><span class="ln">5</span><span class="cl">tags: [feature, announcement]
</span></span><span class="line"><span class="ln">6</span><span class="cl">---
</span></span></code></pre><h2 id="listssh"><a class="anchor" href="#listssh" rel="nofollow">#</a> lists.sh</h2>
<pre><code>=: title Tag support launched
=: description writers can now tag posts for prose and lists
=: publish_at 2022-08-02
=: tags feature, announcement
</code></pre>
<p>When tags are added to a post, users can see the tags on a post. When a user
clicks on a tag, it will take them to the writers main blog page, filtering
posts by the tag.</p>
<p>Right now we only support filtering posts by a single tag, but we want to hear
from you if you'd like to filter by multiple tags.</p>
<p>Filtering by tag is also supported for RSS feeds. For example:
<a href="/rss?tag=feature" rel="nofollow">rss?tag=feature</a></p>
<p>This feature was important for us to implement because we are going to leverage
tagging for a new service we are building <code>imgs.sh</code> which is a premium image
hosting service. Creating photo albums will created by tagging images. Since we
are implementing it for <code>imgs.sh</code> we decided to back port it to <code>prose.sh</code> and
<code>lists.sh</code>.</p>
<p>We are beginning to bear fruit for our monorepo architecture that we discussed
in our previous <a href="/status-update-2022-08-01" rel="nofollow">status update post</a>.</p>
<h2 id="fin"><a class="anchor" href="#fin" rel="nofollow">#</a> fin</h2>
<p>We want to hear from you, so let us know what services or features you think we
should work on next.</p>
<hr/>
<p>Join our <a href="https://pico.sh/irc" rel="nofollow">irc <span class="hashtag">#pico</span>.sh on libera</a> or email us at
<a href="mailto:~erock/pico.sh@lists.sr.ht" rel="nofollow">~erock/pico.sh@lists.sr.ht</a>.</p>
<p>Be sure to subscribe to our <a href="/rss" rel="nofollow">rss feed</a> to get the latest updates at team
pico.</p>
writers can now tag posts for prose and listsCustom CSS2022-07-26T03:02:43Zhttps://hey.prose.sh/custom-css<p>We've heard from a few people that they would like to customize their blog a
little more with their own theme.</p>
<p>It was a simple enough feature to build so I spent an hour or so adding it to
prose.sh.</p>
<p><a href="https://git.sr.ht/~erock/prose.sh/commit/24a38b45d0632c6c26e719aa4c77b6acc" rel="nofollow">git commit</a></p>
<p>I'm sure we'll get requests to support it in our other services, but for now
we're going to pilot test it here.</p>
<p>All you have to do is create a file <code>_styles.css</code> and <code>scp</code> it to prose.</p>
<pre><code>scp _styles.css <username>@prose.sh:/
</code></pre>
<p>See <a href="https://prose.sh/help#blog-style" rel="nofollow">this help section</a> for the full details.</p>
<p>We're excited to see what kind of themes we see in the wild so please feel free
to share it with us at <a href="https://web.libera.chat/#pico.sh" rel="nofollow"><span class="hashtag">#pico</span>.sh on libera</a> or
<a href="mailto:hello@prose.sh" rel="nofollow">email us</a>.</p>
<hr/>
<p>Join our <a href="https://pico.sh/irc" rel="nofollow">irc <span class="hashtag">#pico</span>.sh on libera</a> or email us at
<a href="mailto:~erock/pico.sh@lists.sr.ht" rel="nofollow">~erock/pico.sh@lists.sr.ht</a>.</p>
<p>Be sure to subscribe to our <a href="/rss" rel="nofollow">rss feed</a> to get the latest updates at team
pico.</p>
blogs can customize their themeOperations update2022-07-22T14:43:19Zhttps://hey.prose.sh/ops-update<p>We wanted to send a quick update to let everyone know we have slightly adjusted
our ops page to reflect a recent change to the prose platform.</p>
<p>We received a bunch of requests asking to make the discovery feed a little
easier to find useful posts. We also want to provide bloggers with the ability
to see how well a post is performing.</p>
<p>In that vein we decided to hook up some basic anonymous analytics. This required
a slight change to our ethical position. Right now all we are tracking are
anonymous view counts for posts. This will provide us with some metric data to
better rank the discovery feed. We are only interested in tracking post
performance via anonymous means.</p>
<p><a href="https://git.sr.ht/~erock/prose.sh/commit/168d967f9811aba2302797e278b5617b9e45ad36" rel="nofollow">See the changes here.</a></p>
<p>We understand this might not be what everyone wants and we had quite a few
discussions about it in our
<a href="https://web.libera.chat/#pico.sh" rel="nofollow">irc <span class="hashtag">#pico</span>.sh channel</a>. If you feel strongly
about this change please join our IRC channel or send us an email at
<a href="mailto:hello@pico.sh" rel="nofollow">hello@pico.sh</a>.</p>
<p>We are taking the prose platform seriously and care what bloggers think.</p>
<p>Thanks!</p>
<hr/>
<p>Join our <a href="https://pico.sh/irc" rel="nofollow">irc <span class="hashtag">#pico</span>.sh on libera</a> or email us at
<a href="mailto:~erock/pico.sh@lists.sr.ht" rel="nofollow">~erock/pico.sh@lists.sr.ht</a>.</p>
<p>Be sure to subscribe to our <a href="/rss" rel="nofollow">rss feed</a> to get the latest updates at team
pico.</p>
Adding anonymous post analytics to proseLight theme2022-07-22T01:37:25Zhttps://hey.prose.sh/light-theme<p>Greetings,</p>
<p>We wanted to let everyone know that we have added a new light theme to prose!</p>
<p>Don't worry, we didn't ditch the dark theme, prose respects the
<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme" rel="nofollow">prefers-color-scheme</a>
property.</p>
<p>We considered putting a toggle on the website but most of the solutions we
thought about didn't really fit the vibe of prose. Namely, we don't want to use
javascript or cookies.</p>
<p>We figured this would be a happy medium for users.</p>
<hr/>
<p>Join our <a href="https://pico.sh/irc" rel="nofollow">irc <span class="hashtag">#pico</span>.sh on libera</a> or email us at
<a href="mailto:~erock/pico.sh@lists.sr.ht" rel="nofollow">~erock/pico.sh@lists.sr.ht</a>.</p>
<p>Be sure to subscribe to our <a href="/rss" rel="nofollow">rss feed</a> to get the latest updates at team
pico.</p>
A new light theme that respects prefers-color-schemeCustom domains2022-07-18T20:25:39Zhttps://hey.prose.sh/custom-domains<p>It's been a pretty exciting week for us at the pico.sh headquarters.</p>
<p>We made it to the front-page of
<a href="https://news.ycombinator.com/item?id=32128013" rel="nofollow">hackernews</a>!</p>
<p><img src="https://pbs.twimg.com/media/FX9masGXoAAbbuA?format=jpg&name=small" alt="front-page of hacker news" title="front-page of hackernews"></p>
<p>We were so excited about the launched that we announced in the thread support
for custom domains landed.</p>
<p>We figured it would be a good idea to officially announce it on our blog.</p>
<h2 id="add-your-custom-domain-today"><a class="anchor" href="#add-your-custom-domain-today" rel="nofollow">#</a> Add your custom domain today!</h2>
<p>Don't want to be bored with the details of how custom domains work?</p>
<p>The full usage guide can be found on our
<a href="https://prose.sh/help#custom-domain" rel="nofollow">help page</a>.</p>
<h2 id="how-it-works"><a class="anchor" href="#how-it-works" rel="nofollow">#</a> How it works</h2>
<p>We decided to go with a solution that didn't require us to store any information
about the custom domain you want to use. Instead, all the user needs to do is
add a <code>TXT</code> record and then point the domain with a <code>CNAME</code> to <code>prose.sh</code>.</p>
<p>Under the hood we use
<a href="https://caddyserver.com/docs/automatic-https#on-demand-tls" rel="nofollow">Caddy's on-demand tls</a>.
On our end, the configuration was very simple using <code>Caddyfile</code>:</p>
<pre><code>{
on_demand_tls {
ask http://web:3000/check
interval 1m
burst 10
}
}
:443 {
reverse_proxy web:3000
tls hello@prose.sh {
on_demand
}
encode zstd gzip
}
</code></pre>
<p>The endpoint referenced in the above Caddyfile points to this golang function:</p>
<pre class="chroma"><code><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kd">func</span> <span class="nf">checkHandler</span><span class="p">(</span><span class="nx">w</span> <span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span> <span class="nx">r</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"> <span class="nx">dbpool</span> <span class="o">:=</span> <span class="nf">GetDB</span><span class="p">(</span><span class="nx">r</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"> <span class="nx">cfg</span> <span class="o">:=</span> <span class="nf">GetCfg</span><span class="p">(</span><span class="nx">r</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"> <span class="k">if</span> <span class="nx">cfg</span><span class="p">.</span><span class="nf">IsCustomdomains</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"> <span class="nx">hostDomain</span> <span class="o">:=</span> <span class="nx">r</span><span class="p">.</span><span class="nx">URL</span><span class="p">.</span><span class="nf">Query</span><span class="p">().</span><span class="nf">Get</span><span class="p">(</span><span class="s">"domain"</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"> <span class="nx">appDomain</span> <span class="o">:=</span> <span class="nx">strings</span><span class="p">.</span><span class="nf">Split</span><span class="p">(</span><span class="nx">cfg</span><span class="p">.</span><span class="nx">ConfigCms</span><span class="p">.</span><span class="nx">Domain</span><span class="p">,</span> <span class="s">":"</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"> <span class="k">if</span> <span class="p">!</span><span class="nx">strings</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="nx">hostDomain</span><span class="p">,</span> <span class="nx">appDomain</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"> <span class="nx">subdomain</span> <span class="o">:=</span> <span class="nf">GetCustomDomain</span><span class="p">(</span><span class="nx">hostDomain</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"> <span class="k">if</span> <span class="nx">subdomain</span> <span class="o">!=</span> <span class="s">""</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"> <span class="nx">u</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">dbpool</span><span class="p">.</span><span class="nf">FindUserForName</span><span class="p">(</span><span class="nx">subdomain</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"> <span class="k">if</span> <span class="nx">u</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="o">&&</span> <span class="nx">err</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"> <span class="nx">w</span><span class="p">.</span><span class="nf">WriteHeader</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusOK</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"> <span class="k">return</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">
</span></span><span class="line"><span class="ln">21</span><span class="cl"> <span class="nx">w</span><span class="p">.</span><span class="nf">WriteHeader</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusNotFound</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="p">}</span>
</span></span></code></pre><p>This function does a couple of things. It gets the current domain from the
request and then performs a <code>TXT</code> lookup via <code>GetCustomDomain</code>:</p>
<pre class="chroma"><code><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kd">func</span> <span class="nf">GetCustomDomain</span><span class="p">(</span><span class="nx">host</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">string</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"> <span class="nx">records</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">net</span><span class="p">.</span><span class="nf">LookupTXT</span><span class="p">(</span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">"_prose.%s"</span><span class="p">,</span> <span class="nx">host</span><span class="p">))</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"> <span class="k">return</span> <span class="s">""</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"> <span class="k">for</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">v</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">records</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"> <span class="k">return</span> <span class="nx">strings</span><span class="p">.</span><span class="nf">TrimSpace</span><span class="p">(</span><span class="nx">v</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"> <span class="k">return</span> <span class="s">""</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">}</span>
</span></span></code></pre><p>If the username matches then we respond with a success status. That's really all
there is to it.</p>
<p>It's amazing how far we've come with TLS, isn't it?</p>
<h2 id="wrap-up"><a class="anchor" href="#wrap-up" rel="nofollow">#</a> Wrap up</h2>
<p>This is just one of many features we have planned to make prose.sh awesome. We
also have a handful of
<a href="https://todo.sr.ht/~erock/pico.sh?search=status%3Aopen%20label%3A%22service%22" rel="nofollow">sibling services</a>
we are thinking about building.</p>
<hr/>
<p>Join our <a href="https://pico.sh/irc" rel="nofollow">irc <span class="hashtag">#pico</span>.sh on libera</a> or email us at
<a href="mailto:~erock/pico.sh@lists.sr.ht" rel="nofollow">~erock/pico.sh@lists.sr.ht</a>.</p>
<p>Be sure to subscribe to our <a href="/rss" rel="nofollow">rss feed</a> to get the latest updates at team
pico.</p>
it's as easy as a DNS entry