add new blogs
This commit is contained in:
@@ -12,30 +12,6 @@ body {
|
|||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
header,
|
|
||||||
.blur-background::before {
|
|
||||||
background-image: url(~/assets/images/header.jpg);
|
|
||||||
background-position: center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blur-background {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.blur-background::before {
|
|
||||||
content: '';
|
|
||||||
margin: -35px;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
filter: blur(16px) saturate(115%);
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
@apply text-rose-500 hover:underline visited:bg-rose-700;
|
@apply text-rose-500 hover:underline visited:bg-rose-700;
|
||||||
}
|
}
|
||||||
@@ -51,15 +27,6 @@ samp {
|
|||||||
font-family: 'JetBrains Mono', monospace;
|
font-family: 'JetBrains Mono', monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
.font-inter {
|
|
||||||
font-family: 'Inter';
|
|
||||||
}
|
|
||||||
|
|
||||||
.blog-post-img {
|
|
||||||
border-top-left-radius: 0.5rem;
|
|
||||||
border-top-right-radius: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.text-overflow:before {
|
.text-overflow:before {
|
||||||
content: "";
|
content: "";
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
|
<template>
|
||||||
|
<div :aria-label="name"
|
||||||
|
class="font-inter md:text-lg w-fit max-h-9 min-w-fit bg-zinc-800 border border-zinc-700/30 py-1 px-2 rounded shadow flex items-center"
|
||||||
|
:class="(isTag) ? 'select-none' : 'select-text'"
|
||||||
|
:style="(size) ? 'font-size: ' + size + 'px;' : ''">
|
||||||
|
<Icon :size="(size) ? size : '20'"
|
||||||
|
class="mr-2"
|
||||||
|
:name="(isTag) ? ('logos:' + (tagMap[iconName.toLowerCase().split(' ').join('-')] || iconName.toLowerCase())) : iconName" />
|
||||||
|
{{ name }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.font-inter {
|
||||||
|
font-family: 'Inter', arial, helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
@@ -22,14 +40,3 @@ export default {
|
|||||||
props: ['iconName', 'name', 'isTag', 'size']
|
props: ['iconName', 'name', 'isTag', 'size']
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
|
||||||
<div :aria-label="name"
|
|
||||||
class="font-inter md:text-lg w-fit max-h-9 min-w-fit bg-zinc-800 border border-zinc-700/30 py-1 px-2 rounded shadow flex items-center"
|
|
||||||
:class="(isTag) ? 'select-none' : 'select-text'"
|
|
||||||
:style="(size) ? 'font-size: ' + size + 'px;' : ''">
|
|
||||||
<Icon :size="(size) ? size : '20'"
|
|
||||||
class="mr-2"
|
|
||||||
:name="(isTag) ? ('logos:' + (tagMap[iconName.toLowerCase().split(' ').join('-')] || iconName.toLowerCase())) : iconName" />
|
|
||||||
{{ name }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<code lang="js">
|
<code>
|
||||||
<slot />
|
<slot />
|
||||||
</code>
|
</code>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
202
content/blog/100DaysOfCode-challenge.md
Normal file
202
content/blog/100DaysOfCode-challenge.md
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
---
|
||||||
|
title: My 100DaysOfCode Challenge
|
||||||
|
description: A review of my 100DaysOfCode challenge
|
||||||
|
image:
|
||||||
|
src: '/images/100DaysOfCode-overview.png'
|
||||||
|
alt: 'How I made my site fast'
|
||||||
|
head:
|
||||||
|
meta:
|
||||||
|
- name: 'keywords'
|
||||||
|
content: 'web dev, nodejs'
|
||||||
|
- name: 'robots'
|
||||||
|
content: 'index, follow'
|
||||||
|
- name: 'author'
|
||||||
|
content: 'juls07'
|
||||||
|
- name: 'copyright'
|
||||||
|
content: '© 2022 juls07'
|
||||||
|
date: 2023-01-02
|
||||||
|
tags:
|
||||||
|
- web dev
|
||||||
|
- nodejs
|
||||||
|
---
|
||||||
|
|
||||||
|
For my #100DaysOfCode challenge on [twitter](https://twitter.com/julie4055_) I decided to make a UI framework similar to vue.js (terrible idea). For day 1 it started simple with learning about reactivity, a short read of this [great blog post](https://lihautan.com/reactivity-in-web-frameworks-the-when/) by Tan Li Hau I had a basic trackable object function in the script.js file. For day 2 I had covered a few more things in the UI framework world, I had a templating system, a basic virtualDOM-like implementation,<!--more--> a [different reactive prop function](https://dev.to/siddharthshyniben/implementing-reactivity-from-scratch-51op) from siddharth, and we had a basic click directive working, great work so far. Day 3 and 4 are kinda lame, on day 3 I added a model directive similar to vue.js' v-model and on day 4 I changed the way templates were handled so I could have text before the template and I started trying to be like JSX (lmao), kinda lame and basic IMO. Now day 5 I learned about SPA routing, very simple routing that just changed the page link and rendered the template from the new page. Day 6-9 is more boring shit, simple things like a once attribute, an html attribute, etc etc. But on day 10 I learned about conditional rendering, this was an amazing learning experience for me, it taught me loads about recursive functions and how recursive functions should be used. skipping over day 11 because I added a few more directives on day 12 I made a mounted function similar to vue.js' mounted function except for the fact that it was made by me so it was terrible XD. On day 13 crazy thing happened, I decided to stop pretending to be JSX and made template files using SSR, SSR was very simple to get working, basically I just pre-rendered the page and sent the page to the client, pretty simple, but SSR would give me many more opportunities in the future of this project. skipping over day 14-20 (can you tell I was loosing motivation fast or what?) on day 21 we actually got some code gen on the server side, very simple but still pretty cool in my opinion, here's the code I shared on day 21
|
||||||
|
|
||||||
|
```ts[index.ts]
|
||||||
|
template = template.replace('<script async src="/src/entry-client.ts" type="module"></script>', '');
|
||||||
|
|
||||||
|
template = template.replace('id="app"', 'id="app" data-server-rendered="true"');
|
||||||
|
|
||||||
|
let scriptedTemplate = template;
|
||||||
|
|
||||||
|
const { renderSSRHydrationCode } = await vite.ssrLoadModule(basepath.slice(1) + 'lib/router/ssrHydrationGenerator');
|
||||||
|
|
||||||
|
const code = await renderSSRHydrationCode(eval(appHtml.fnStr));
|
||||||
|
|
||||||
|
if (appHtml.script || code) {
|
||||||
|
scriptedTemplate = template.replace('<!--script-outlet-->', '<script async type="module">' + appHtml.script + code + '</script>');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Very simple code but I still think it's pretty cool and a milestone in the project. Skipping day 22 to 47 (yeah, really got that amazing motivation) becausse it was all basically bug fixes or boring things, but on day 48 I got slot functions, well slot functions made by me working so yeah... the code is pretty bad for that, but it works and that's all that matters right? On day 50 I got a cool little image bundling feature working, I think it's pretty cool that the images can be baked into the page response, the code is bad and not very readable but it's a pretty cool feature, here's the code for that, the original version that only rendered svgs tho.
|
||||||
|
|
||||||
|
```ts[index.ts]
|
||||||
|
function renderSVGToBase64(element: string) {
|
||||||
|
const fixedElm = element.split('>')[0];
|
||||||
|
if (!fixedElm) return false;
|
||||||
|
if (fixedElm.split(' ').length < 2) return false;
|
||||||
|
if (!fixedElm.includes('svg:bundle')) return false;
|
||||||
|
let srcName = fixedElm.split('src')[1]?.split(' ')[0]?.slice(2);
|
||||||
|
if (!srcName) return;
|
||||||
|
srcName = srcName.slice(0, srcName.length - 2);
|
||||||
|
if (!srcName.includes('.svg')) return srcName;
|
||||||
|
const svgBlob = fs.readFileSync(path.resolve(__dirname, './public' + srcName));
|
||||||
|
return { data: ('data:image/svg+xml;base64,' + svgBlob.toString('base64')), srcName };
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
On day 52 I learned about memoization, although at the time I didn't know it was memoization so I just called it a page cache, here's the code using the LRUCache implementation from [@trunarla](https://twitter.com/trunarla) on twitter I used to cache pages.
|
||||||
|
|
||||||
|
```ts[pageRendered.ts]
|
||||||
|
if (cachedFile) {
|
||||||
|
if (import.meta.env.VITE_VERBOSE && !import.meta.env.PROD && !import.meta.env.SSR) {
|
||||||
|
console.groupCollapsed(`Loaded page ${dir}${url} from cache`);
|
||||||
|
console.log(cachedFile);
|
||||||
|
console.groupEnd();
|
||||||
|
}
|
||||||
|
file = cachedFile;
|
||||||
|
} else {
|
||||||
|
// fetch page via the internet
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Skipping past day 53 to day 78 (yeah, really motivated) since those days were just more bug fixes and such. On day 79 though, I learned about proxies and fixed an issue with accessing objects in the appState, here's the modified Reactive object class that I refactored.
|
||||||
|
|
||||||
|
```ts[ReactiveObject.ts]
|
||||||
|
export class Reactive {
|
||||||
|
listeners: Record<string, Array<CallableFunction>>;
|
||||||
|
contents: Record<string, unknown>;
|
||||||
|
|
||||||
|
constructor(obj: Record<string, any>) {
|
||||||
|
const createProxy = (target: any, propName: string) => {
|
||||||
|
if (propName !== '') {
|
||||||
|
propName = propName + '.';
|
||||||
|
}
|
||||||
|
function proxyObjects(obj: any) {
|
||||||
|
if (typeof obj !== 'object') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(obj).forEach((key) => {
|
||||||
|
if (typeof obj[key] == 'object') {
|
||||||
|
proxyObjects(obj[key]);
|
||||||
|
obj[key] = createProxy(obj[key], `${propName}${key}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyObjects(target);
|
||||||
|
|
||||||
|
return new Proxy(target, {
|
||||||
|
set: (target, key, value) => {
|
||||||
|
if (typeof value === 'object') {
|
||||||
|
// Recursively create a proxy for nested objects
|
||||||
|
value = createProxy(value, `${propName}${key.toString()}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof key !== 'string') return false;
|
||||||
|
|
||||||
|
target[key] = value;
|
||||||
|
this.notify(`${propName}${key}`);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.contents = createProxy(obj, '');
|
||||||
|
this.listeners = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
listen(prop: string, handler: CallableFunction) {
|
||||||
|
if (!this.listeners[prop]) this.listeners[prop] = [];
|
||||||
|
|
||||||
|
this.listeners[prop]?.push(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
notify(prop: string) {
|
||||||
|
if (!this.listeners[prop]) return;
|
||||||
|
|
||||||
|
// Split the property name into its nested parts
|
||||||
|
const propParts = prop.split('.');
|
||||||
|
|
||||||
|
// Get the value of the nested property on the contents object
|
||||||
|
let value: any = this.contents;
|
||||||
|
propParts.forEach((part) => {
|
||||||
|
value = value[part];
|
||||||
|
});
|
||||||
|
|
||||||
|
this.listeners[prop]?.forEach((listener: CallableFunction) => listener(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
On day 88 I changed my hydration so instead of manually typing the event listeners to look for I am able to loop over the page elements and automatically add event listeners to them based on their attributes, here's the code I wrote for that function, this function would later become the all encompassing function to hydrate every element on the page, but we're not their yet.
|
||||||
|
|
||||||
|
```ts[hydrationManager.ts]
|
||||||
|
export function hydrateElements(appState: Reactive) {
|
||||||
|
const elements = Array.from(document.getElementById('app').querySelectorAll('*'));
|
||||||
|
|
||||||
|
const eventElements = elements.filter((e) => {
|
||||||
|
return Array.from(e.attributes).some(attr => attr.name.startsWith('d-on:'));
|
||||||
|
});
|
||||||
|
|
||||||
|
eventElements.forEach((e) => {
|
||||||
|
const dOnAttrs = Array.from(e.attributes).filter(attr => attr.name.startsWith('d-on:'));
|
||||||
|
|
||||||
|
dOnAttrs.forEach((attr) => {
|
||||||
|
const [eventType, ...modifiers] = attr.name.split(':')[1].split('.');
|
||||||
|
const code = attr.value;
|
||||||
|
const isKeyboardEvent = (eventType.startsWith('key')) ? true : false;
|
||||||
|
const keyName = (isKeyboardEvent && modifiers[0]) ? modifiers[0].charAt(0).toUpperCase() + modifiers[0].slice(1).toLowerCase() : '';
|
||||||
|
e.removeAttribute(attr.name);
|
||||||
|
|
||||||
|
e.addEventListener(eventType, (event) => {
|
||||||
|
let eventKey = event.key;
|
||||||
|
if (isKeyboardEvent && eventKey === ' ') {
|
||||||
|
eventKey = 'Space';
|
||||||
|
}
|
||||||
|
const firstLetter = eventKey.split('')[0];
|
||||||
|
eventKey = firstLetter?.toUpperCase() + eventKey.slice(1).toLowerCase();
|
||||||
|
|
||||||
|
for (let i = 0; i < modifiers.length; i++) {
|
||||||
|
const modifier = modifiers[i];
|
||||||
|
|
||||||
|
if (modifier === 'stop') {
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modifier === 'prevent') {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modifier === 'self') {
|
||||||
|
if (e !== event.target) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isKeyboardEvent || !keyName) {
|
||||||
|
eval(code);
|
||||||
|
} else if (eventKey === keyName) {
|
||||||
|
eval(code);
|
||||||
|
}
|
||||||
|
}, { once: modifiers.some(mod => mod === 'once'), capture: modifiers.some(mod => mod === 'capture'), passive: modifiers.some(mod => mod === 'passive') });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
On day 95 I completely consolidated the hydration function to reduce the amount of loops I call to hydrate the elements on the page. On day 98 I learned about real Virtual DOMs and the advantage of virtual DOMs, this is where in the project I was telling myself "fuck it, I should completely restart the whole project later and fix all of the dirty nasty code I have written.", but I continued the project as normal knowing that completely restarting the whole project would be much more than a 1 day process. And that's it, a brief overview of my 100DaysOfCode challenge.
|
||||||
|
<br />
|
||||||
|
## Overview
|
||||||
|
In the end of this project I feel more motivated to learn more about frameworks and everything related to that, a reflection coming soon to my [twitter](https://twitter.com/julie4055_) so keep an eye out if you're interested in that, after all that I hope you enjoyed reading.
|
||||||
|
<br/>
|
||||||
|
<p class="text-xl font-extrabold"><a href="https://twitch.tv/julie4055_">To be continued...?</a></p>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
title: Rebuilding my personal website!
|
title: Rebuilding my personal website!
|
||||||
description: My experiences with nuxtjs 3 and tRPC
|
description: My experiences with nuxtjs 3 and tRPC
|
||||||
image:
|
image:
|
||||||
src: '/images/how-i-made-my-site-fast.png'
|
src: '/images/full-website-rebuild.png'
|
||||||
alt: 'placeholder'
|
alt: 'placeholder'
|
||||||
head:
|
head:
|
||||||
meta:
|
meta:
|
||||||
@@ -14,11 +14,12 @@ head:
|
|||||||
content: 'juls07'
|
content: 'juls07'
|
||||||
- name: 'copyright'
|
- name: 'copyright'
|
||||||
content: '© 2022 juls07'
|
content: '© 2022 juls07'
|
||||||
date: 2022-09-20
|
date: 2023-01-02
|
||||||
_draft: true
|
|
||||||
tags:
|
tags:
|
||||||
- web dev
|
- web dev
|
||||||
- nuxtjs 3
|
- nuxtjs 3
|
||||||
---
|
---
|
||||||
|
|
||||||
For the past month I've been quietly rebuilding my portfolio site, designing and building a new site. My previous site was bland and dull, this one is like a whole new world. The old site was just a two colors that don't even go well together, it was clear to me that was no way to present myself. So about halfway though november I started fresh, with Nuxt3 and a whole lot of insomnia in my possession I went to figma to design my new site. <!--more--> After a couple days of making a design in figma I setup a new nuxt3 project and went to work, after just a few weeks I had almost everything completed, but the last few things I had to do were to make the blogs page and finish the project cards. After a few weeks of designing and getting feedback from the [web dev and design]( https://discord.gg/web) discord server, mainly feedback from aqil#7927 an absolute machine in the visual design help channel. However, rebuilding the site still wasn't done, so about halfway through december I decided to change a few things, the typing animation on the home page was added that day and a few accessibility things here and there.
|
For the past month I've been quietly rebuilding my portfolio site, designing and building a new site. My previous site was bland and dull, this one is like a whole new world. The old site was just a two colors that don't even go well together, it was clear to me that was no way to present myself. So about halfway though november I started fresh, with Nuxt3 and a whole lot of insomnia in my possession I went to figma to design my new site. <!--more--> After a couple days of making a design in figma I setup a new nuxt3 project and went to work, after just a few weeks I had almost everything completed, but the last few things I had to do were to make the blogs page and finish the project cards. After a few weeks of designing and getting feedback from the [web dev and design]( https://discord.gg/web) discord server, mainly feedback from aqil#7927 an absolute machine in the visual design help channel. However, rebuilding the site still wasn't done, so about halfway through december I decided to change a few things, the typing animation on the home page was added that day and a few accessibility things here and there.
|
||||||
|
<br />
|
||||||
|
Once 2023 hit I started working on this much more, with my [100DaysOfCode Challenge](/blog/100daysofcode-challenge) completed I had much more time to work on this site. Mostly I just had to finish writing a few blog posts, and I would be able to finally publish the new site. So I got to writing this blog post and here we are right now. This post is just an update with the new site, here's the sites [github](https://github.com/juls0730/juls07.dev-v2) and that's all, checkout my [twitter](https://twitter.com/julie4055_) if you want to hear more about what I do, have a great 2023!
|
||||||
@@ -23,7 +23,7 @@ tags:
|
|||||||
---
|
---
|
||||||
|
|
||||||
Recently, I started running a qbittorrent webserver on my raspberry pi 4B+ using [this docker image](https://hotio.dev/containers/qbittorrent/), It has been quite a journey. First, I started looking for a way to run a qbittorrent in a container, this is how I run all the applications on my raspberry pi and I inevibly asked in the [Arch linux discord server](https://discord.gg/3m6dbPR) and I got a reply from @runsamok on discord and they reccomend the docker image I mentioned earlier.<!--more--> Then I started seeding linux distros (obviously) and I started with a batch of about 7 give or take, Ubuntu 18.04, Ubuntu 20.04, Ubuntu 21.04, Arch Linux (duh), Rocky Linux, and tails linux. I shotly realized that Rocky and tails are baren wastelands when it comes to people wanting to torrent them so I eventually Scrapped them.
|
Recently, I started running a qbittorrent webserver on my raspberry pi 4B+ using [this docker image](https://hotio.dev/containers/qbittorrent/), It has been quite a journey. First, I started looking for a way to run a qbittorrent in a container, this is how I run all the applications on my raspberry pi and I inevibly asked in the [Arch linux discord server](https://discord.gg/3m6dbPR) and I got a reply from @runsamok on discord and they reccomend the docker image I mentioned earlier.<!--more--> Then I started seeding linux distros (obviously) and I started with a batch of about 7 give or take, Ubuntu 18.04, Ubuntu 20.04, Ubuntu 21.04, Arch Linux (duh), Rocky Linux, and tails linux. I shotly realized that Rocky and tails are baren wastelands when it comes to people wanting to torrent them so I eventually Scrapped them.
|
||||||
<br class="article"/>
|
<br />
|
||||||
So after about 10 or so days I wanted to automatically download Arch linux and ubuntu updates using RSS, the qbittorrent webserver has thought of that so you can easily so so in the RSS tab. However, When downloading the latest Arch Linux version it worked fine but I added an ubuntu feed that I accidentally downloaded the 10 most recent torrents, but I deleted them and moved on. Later down the road I was trying to download the march patch of the Arch Linux torrent but I could not, after a while of wondering why I realized my storage was full, my raspberry pi doesnt have a lot of storage but not a little, it turns out that the torrents I deleted from the Ubuntu RSS were still on the raspberry pi, this isnt the fault of the developers because I didnt check the "delete on disk" button but there was not "not enough space warning" message when I tried to download the Arch Linux torrent.
|
So after about 10 or so days I wanted to automatically download Arch linux and ubuntu updates using RSS, the qbittorrent webserver has thought of that so you can easily so so in the RSS tab. However, When downloading the latest Arch Linux version it worked fine but I added an ubuntu feed that I accidentally downloaded the 10 most recent torrents, but I deleted them and moved on. Later down the road I was trying to download the march patch of the Arch Linux torrent but I could not, after a while of wondering why I realized my storage was full, my raspberry pi doesnt have a lot of storage but not a little, it turns out that the torrents I deleted from the Ubuntu RSS were still on the raspberry pi, this isnt the fault of the developers because I didnt check the "delete on disk" button but there was not "not enough space warning" message when I tried to download the Arch Linux torrent.
|
||||||
<br class="article"/>
|
<br />
|
||||||
Finally, after everything you're probably asking yourself if you should also host a bittorrent server, you should just as long as you have the free bandwidth and some extra computing power available. The Docker image I choose only takes about 30% cpu max so if you have a raspberry pi laying around it might be the perfect time to setup a bittorrent server. Thanks for reading if you havent already go ahead and follow my twitter [@julie4055_](https://twitter.com/julie4055_) and that'll be it have a great rest of your day!
|
Finally, after everything you're probably asking yourself if you should also host a bittorrent server, you should just as long as you have the free bandwidth and some extra computing power available. The Docker image I choose only takes about 30% cpu max so if you have a raspberry pi laying around it might be the perfect time to setup a bittorrent server. Thanks for reading if you havent already go ahead and follow my twitter [@julie4055_](https://twitter.com/julie4055_) and that'll be it have a great rest of your day!
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ tags:
|
|||||||
---
|
---
|
||||||
|
|
||||||
So I have been working on a social media site I am currently calling snowballsocial, so far I have users, posts, replies, and likes. Expressjs not having HTTP/2 is slightly annoying and I have kind of thought migrating all of my code to hapi but I'm too lazy to migrate all my code right now, especially since I just "asyncified" it, remaking my code rather than making all new code would probably be easier but I'll do that later.<!--more--> This project I again used mongoDB, I fist used mongodb in my [vuefullstack](https://github.com/juls0730/vuefullstack) app, and I loved it, it's much easier for the kind of projects I use than mySQL. Actually targeting a production site rather than just having fun like with my vuefullstack app or my rails-forum, etc. make me worry about alot more thigs like SEO, I tried to add OG tags to the post-show tag just showing post data but it doesnt work because the tags are added after the data loads.
|
So I have been working on a social media site I am currently calling snowballsocial, so far I have users, posts, replies, and likes. Expressjs not having HTTP/2 is slightly annoying and I have kind of thought migrating all of my code to hapi but I'm too lazy to migrate all my code right now, especially since I just "asyncified" it, remaking my code rather than making all new code would probably be easier but I'll do that later.<!--more--> This project I again used mongoDB, I fist used mongodb in my [vuefullstack](https://github.com/juls0730/vuefullstack) app, and I loved it, it's much easier for the kind of projects I use than mySQL. Actually targeting a production site rather than just having fun like with my vuefullstack app or my rails-forum, etc. make me worry about alot more thigs like SEO, I tried to add OG tags to the post-show tag just showing post data but it doesnt work because the tags are added after the data loads.
|
||||||
<br class="article"/>
|
<br />
|
||||||
I've gotten a VPS from [linode](https://linode.com) so I could expose my non-static only page to the internet without exposing my home IP address, making me vulnerable to being doxxed and DDoS attacks. Using nignx I have reverse-proxied my api from port 3001 to 2087, and added ssl certs, and I have used it to server my static site on port 80, I have used nginx before and it's pretty simple to use. Optimizing has been the bain of development so far, making api requests faster, and reducing bundle size, I'm going to focus on api optimizations since its the harder one. My main worry for more than a couple requests is getting posts, since I do a for loop to change userId's to usernames
|
I've gotten a VPS from [linode](https://linode.com) so I could expose my non-static only page to the internet without exposing my home IP address, making me vulnerable to being doxxed and DDoS attacks. Using nignx I have reverse-proxied my api from port 3001 to 2087, and added ssl certs, and I have used it to server my static site on port 80, I have used nginx before and it's pretty simple to use. Optimizing has been the bain of development so far, making api requests faster, and reducing bundle size, I'm going to focus on api optimizations since its the harder one. My main worry for more than a couple requests is getting posts, since I do a for loop to change userId's to usernames
|
||||||
```js
|
```js
|
||||||
for (let i = 0; i < posts.length; i++) {
|
for (let i = 0; i < posts.length; i++) {
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ tags:
|
|||||||
---
|
---
|
||||||
|
|
||||||
I started using linux about 3 years ago, I started with Pop!_OS but after that I switched to fedora, then Zorin which is still the most beautiful out of the box linux distro I have ever used. After that howerver, I switched to arch and I've been on my misadventure's with arch for about 2 years now. I have a very minimalist approach to linux, trying to save as much space as possible save as much computer power as possible, arch being an extremely minimal install of linux was great for me.<!--more--> Next, being able to customize the install of arch is great, dont like systemd because of the company behind it, try runit or openrc, want btrfs so you can compress your files, go ahead, dont want grub, try systemdboot, etc. It's just the way arch lets you do whatever you want. Then, its the support from the [community discord](https://discord.gg/3m6dbPR) or the [arch wiki](https://wiki.archlinux.org/title/Main_page) if someone has had that problem theres a good chance you can get it fixed.
|
I started using linux about 3 years ago, I started with Pop!_OS but after that I switched to fedora, then Zorin which is still the most beautiful out of the box linux distro I have ever used. After that howerver, I switched to arch and I've been on my misadventure's with arch for about 2 years now. I have a very minimalist approach to linux, trying to save as much space as possible save as much computer power as possible, arch being an extremely minimal install of linux was great for me.<!--more--> Next, being able to customize the install of arch is great, dont like systemd because of the company behind it, try runit or openrc, want btrfs so you can compress your files, go ahead, dont want grub, try systemdboot, etc. It's just the way arch lets you do whatever you want. Then, its the support from the [community discord](https://discord.gg/3m6dbPR) or the [arch wiki](https://wiki.archlinux.org/title/Main_page) if someone has had that problem theres a good chance you can get it fixed.
|
||||||
<br class="article"/>
|
<br />
|
||||||
Overall, I know that arch isnt good for industrial applications since it doesnt scale well, its definitely for enthusiasts who have the time to work on their computer and not for linux novices. I love arch for its simplicity and flexibility and I think you should try it if your used to linux and want something new to play with. Using arch over the years has taught me so much about linux in general and if your a seasoned linux user give it a change, maybe you'll find the same love for it I did all the years ago.
|
Overall, I know that arch isnt good for industrial applications since it doesnt scale well, its definitely for enthusiasts who have the time to work on their computer and not for linux novices. I love arch for its simplicity and flexibility and I think you should try it if your used to linux and want something new to play with. Using arch over the years has taught me so much about linux in general and if your a seasoned linux user give it a change, maybe you'll find the same love for it I did all the years ago.
|
||||||
<br class="article"/>
|
<br />
|
||||||
Thanks for reading, if you liked it go ahead and follow me on twitter [@julie4055_](https://twitter.com/julie4055_) or maybe just tell me how bad I am at
|
Thanks for reading, if you liked it go ahead and follow me on twitter [@julie4055_](https://twitter.com/julie4055_) or maybe just tell me how bad I am at
|
||||||
making banners for my blogs, peace.
|
making banners for my blogs, peace.
|
||||||
|
|||||||
@@ -30,6 +30,10 @@ export default defineNuxtConfig({
|
|||||||
|
|
||||||
modules: ['nuxt-icon', '@nuxt/content'],
|
modules: ['nuxt-icon', '@nuxt/content'],
|
||||||
|
|
||||||
|
image: {
|
||||||
|
provider: 'ipx'
|
||||||
|
},
|
||||||
|
|
||||||
nitro: {
|
nitro: {
|
||||||
prerender: {
|
prerender: {
|
||||||
crawlLinks: true,
|
crawlLinks: true,
|
||||||
|
|||||||
69
package-lock.json
generated
69
package-lock.json
generated
@@ -13,6 +13,7 @@
|
|||||||
"nuxt": "3.0.0",
|
"nuxt": "3.0.0",
|
||||||
"nuxt-icon": "^0.1.7",
|
"nuxt-icon": "^0.1.7",
|
||||||
"postcss": "^8.4.19",
|
"postcss": "^8.4.19",
|
||||||
|
"rss": "^1.2.2",
|
||||||
"sitemap": "^7.1.1",
|
"sitemap": "^7.1.1",
|
||||||
"tailwindcss": "^3.2.4"
|
"tailwindcss": "^3.2.4"
|
||||||
}
|
}
|
||||||
@@ -6301,6 +6302,27 @@
|
|||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mime-db": {
|
||||||
|
"version": "1.25.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz",
|
||||||
|
"integrity": "sha512-5k547tI4Cy+Lddr/hdjNbBEWBwSl8EBc5aSdKvedav8DReADgWJzcYiktaRIw3GtGC1jjwldXtTzvqJZmtvC7w==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-types": {
|
||||||
|
"version": "2.1.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz",
|
||||||
|
"integrity": "sha512-ryBDp1Z/6X90UvjUK3RksH0IBPM137T7cmg4OgD5wQBojlAiUwuok0QeELkim/72EtcYuNlmbkrcGuxj3Kl0YQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "~1.25.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/mimic-fn": {
|
"node_modules/mimic-fn": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||||
@@ -8305,6 +8327,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rss": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rss/-/rss-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-xUhRTgslHeCBeHAqaWSbOYTydN2f0tAzNXvzh3stjz7QDhQMzdgHf3pfgNIngeytQflrFPfy6axHilTETr6gDg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"mime-types": "2.1.13",
|
||||||
|
"xml": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/run-async": {
|
"node_modules/run-async": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
||||||
@@ -10185,6 +10217,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/xml": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/xmlhttprequest-ssl": {
|
"node_modules/xmlhttprequest-ssl": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||||
@@ -14885,6 +14923,21 @@
|
|||||||
"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
|
"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"mime-db": {
|
||||||
|
"version": "1.25.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz",
|
||||||
|
"integrity": "sha512-5k547tI4Cy+Lddr/hdjNbBEWBwSl8EBc5aSdKvedav8DReADgWJzcYiktaRIw3GtGC1jjwldXtTzvqJZmtvC7w==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"mime-types": {
|
||||||
|
"version": "2.1.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz",
|
||||||
|
"integrity": "sha512-ryBDp1Z/6X90UvjUK3RksH0IBPM137T7cmg4OgD5wQBojlAiUwuok0QeELkim/72EtcYuNlmbkrcGuxj3Kl0YQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"mime-db": "~1.25.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"mimic-fn": {
|
"mimic-fn": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||||
@@ -16330,6 +16383,16 @@
|
|||||||
"yargs": "^17.5.1"
|
"yargs": "^17.5.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rss": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rss/-/rss-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-xUhRTgslHeCBeHAqaWSbOYTydN2f0tAzNXvzh3stjz7QDhQMzdgHf3pfgNIngeytQflrFPfy6axHilTETr6gDg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"mime-types": "2.1.13",
|
||||||
|
"xml": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"run-async": {
|
"run-async": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
|
||||||
@@ -17693,6 +17756,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
"xml": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"xmlhttprequest-ssl": {
|
"xmlhttprequest-ssl": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"nuxt-icon": "^0.1.7",
|
"nuxt-icon": "^0.1.7",
|
||||||
"postcss": "^8.4.19",
|
"postcss": "^8.4.19",
|
||||||
"sitemap": "^7.1.1",
|
"sitemap": "^7.1.1",
|
||||||
|
"rss": "^1.2.2",
|
||||||
"tailwindcss": "^3.2.4"
|
"tailwindcss": "^3.2.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="pt-6 mb-4 !col-start-2 md:!col-start-3 lg:!col-start-4 lg:col-span-6 md:col-span-8 col-span-10">
|
<div class="pt-6 mb-4 !col-start-2 md:!col-start-3 lg:!col-start-4 lg:col-span-6 md:col-span-8 col-span-10">
|
||||||
<ContentDoc v-slot="{ doc }">
|
<ContentDoc v-slot="{ doc }">
|
||||||
<img :src="doc.image.src"
|
<img :src="doc.image.src"
|
||||||
class="mb-2" />
|
class="mb-2 rounded-md drop-shadow" />
|
||||||
<h1 class="text-3xl text-gray-100 md:text-4xl font-semibold mb-2">{{ doc.title }}</h1>
|
<h1 class="text-3xl text-gray-100 md:text-4xl font-semibold mb-2">{{ doc.title }}</h1>
|
||||||
<p class="mb-1 text-zinc-400">
|
<p class="mb-1 text-zinc-400">
|
||||||
{{ doc.description }}
|
{{ doc.description }}
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<p class="mb-2 text-zinc-500">
|
<p class="mb-2 text-zinc-500">
|
||||||
{{ new Date(doc.date).toDateString().split(' ').slice(1).join(' ') }}
|
{{ new Date(doc.date).toDateString().split(' ').slice(1).join(' ') }}
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-wrap w-full gap-2 justify-start mb-7">
|
<div class="flex flex-wrap w-full gap-2 justify-start mb-3">
|
||||||
<IconTag v-for="tag in doc.tags"
|
<IconTag v-for="tag in doc.tags"
|
||||||
:name="tag"
|
:name="tag"
|
||||||
:iconName='tag'
|
:iconName='tag'
|
||||||
@@ -33,3 +33,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
br {
|
||||||
|
@apply my-3;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
:src="article.image.src"
|
:src="article.image.src"
|
||||||
class="w-full rounded-tl-lg rounded-tr-lg aspect-video" />
|
class="w-full rounded-tl-lg rounded-tr-lg aspect-video" />
|
||||||
<div
|
<div
|
||||||
class="p-3 overflow-hidden pt-2 before:w-full before:h-2/6 before:absolute before:left-0 before:bottom-0 before:bg-gradient-to-b before:from-transparent before:to-[#201F20] mb-1 pb-1 relative">
|
class="p-3 overflow-hidden pt-2 text-fade mb-1 pb-1 relative">
|
||||||
<h3>
|
<h3>
|
||||||
<nuxt-link tabindex="0"
|
<nuxt-link tabindex="0"
|
||||||
class="text-lg"
|
class="text-lg"
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
<p class="text-zinc-500">
|
<p class="text-zinc-500">
|
||||||
{{ new Date(article.date).toDateString().split(' ').slice(1).join(' ') }}
|
{{ new Date(article.date).toDateString().split(' ').slice(1).join(' ') }}
|
||||||
</p>
|
</p>
|
||||||
<p class="text-zinc-200 max-h-56">
|
<p class="text-zinc-200 max-h-[13.75rem]">
|
||||||
<ContentDoc :head="false"
|
<ContentDoc :head="false"
|
||||||
:value="article"
|
:value="article"
|
||||||
:path="article._path"
|
:path="article._path"
|
||||||
@@ -38,8 +38,10 @@
|
|||||||
:iconName='tag'
|
:iconName='tag'
|
||||||
isTag="true" />
|
isTag="true" />
|
||||||
</div>
|
</div>
|
||||||
<ContentRenderer :value="doc"
|
<div class="max-h-full">
|
||||||
:excerpt="true" />
|
<ContentRenderer :value="doc"
|
||||||
|
:excerpt="true" />
|
||||||
|
</div>
|
||||||
</ContentDoc>
|
</ContentDoc>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -50,8 +52,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.text-fade::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 33.333333%;
|
||||||
|
left: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
background-image: linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(12,12,12,0) 36%, rgba(32,31,32,1) 95%, rgba(32,31,32,1) 100%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { data: articles } = await useAsyncData('posts-list', () => queryContent('/blog')
|
const { data: articles } = await useAsyncData('posts-list', () => queryContent('/blog')
|
||||||
|
.only(['image', '_path', 'title', 'description', 'date'])
|
||||||
.where({ _draft: false })
|
.where({ _draft: false })
|
||||||
.sort({ date: -1, $numeric: true, })
|
.sort({ date: -1, $numeric: true, })
|
||||||
.find()
|
.find()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<Nav class="absolute z-10" />
|
<Nav class="absolute z-10" />
|
||||||
<header class="w-full h-3/6 sm:h-2/5 md:h-3/5">
|
<header class="w-full h-3/6 sm:h-2/5 md:h-3/5">
|
||||||
<div
|
<div
|
||||||
class="p-6 bg-[#12121233] justify-center grid sm:grid-cols-12 gap-5 items-center sm:justify-start w-full h-full blur-background">
|
class="p-6 bg-[#1212121A] justify-center grid sm:grid-cols-12 gap-5 items-center sm:justify-start w-full h-full blur-background">
|
||||||
<div
|
<div
|
||||||
class="sm:h-32 sm:!col-start-2 sm:col-span-8 md:col-span-6 lg:col-span-5 w-32 sm:w-fit max-h-full md:h-40 items-center grid grid-rows-1 grid-cols-1 sm:grid-cols-2 drop-shadow-md">
|
class="sm:h-32 sm:!col-start-2 sm:col-span-8 md:col-span-6 lg:col-span-5 w-32 sm:w-fit max-h-full md:h-40 items-center grid grid-rows-1 grid-cols-1 sm:grid-cols-2 drop-shadow-md">
|
||||||
<img alt="juls07 profile picture"
|
<img alt="juls07 profile picture"
|
||||||
@@ -124,6 +124,32 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.blur-background {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blur-background::before {
|
||||||
|
content: '';
|
||||||
|
margin: -35px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
filter: blur(16px) saturate(125%);
|
||||||
|
}
|
||||||
|
|
||||||
|
header,
|
||||||
|
.blur-background::before {
|
||||||
|
background-image: url(~/assets/images/header.jpg);
|
||||||
|
background-position: center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
useHead({
|
useHead({
|
||||||
title: 'Juls07',
|
title: 'Juls07',
|
||||||
|
|||||||
BIN
public/images/100DaysOfCode-overview.png
Normal file
BIN
public/images/100DaysOfCode-overview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.9 MiB |
7
public/robots.txt
Normal file
7
public/robots.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
User-Agent: *
|
||||||
|
Disallow: /*.json
|
||||||
|
Disallow: /*.xml
|
||||||
|
Disallow: /*.rss
|
||||||
|
Allow: /
|
||||||
|
Allow: /sitemap.xml
|
||||||
|
Allow: /blog/*
|
||||||
22
server/routes/.rss.ts
Normal file
22
server/routes/.rss.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { serverQueryContent } from '#content/server'
|
||||||
|
import RSS from 'rss'
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
// Fetch all documents
|
||||||
|
const docs = await serverQueryContent(event).find()
|
||||||
|
const feed = new RSS({
|
||||||
|
title: 'Juls07',
|
||||||
|
description: 'Juls07\'s blogs',
|
||||||
|
link: 'https://juls07.dev/blogs'
|
||||||
|
})
|
||||||
|
|
||||||
|
for (const doc of docs) {
|
||||||
|
feed.item({
|
||||||
|
title: doc.title,
|
||||||
|
description: doc.description,
|
||||||
|
image_url: doc.image.src
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return feed.xml({ indent: true })
|
||||||
|
})
|
||||||
@@ -10,7 +10,8 @@ export default defineEventHandler(async (event) => {
|
|||||||
|
|
||||||
for (const doc of docs) {
|
for (const doc of docs) {
|
||||||
sitemap.write({
|
sitemap.write({
|
||||||
url: doc._path
|
url: doc._path,
|
||||||
|
changefreq: 'monthly'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sitemap.end()
|
sitemap.end()
|
||||||
|
|||||||
Reference in New Issue
Block a user