add blogs, move pictures to local + much more
4
.gitignore
vendored
@@ -6,3 +6,7 @@ node_modules
|
||||
.output
|
||||
.env
|
||||
dist
|
||||
|
||||
# Supabase
|
||||
supabase/.branches
|
||||
supabase/.temp
|
||||
|
||||
@@ -9,27 +9,49 @@
|
||||
html,
|
||||
body {
|
||||
background-color: #191819;
|
||||
color: white;
|
||||
}
|
||||
|
||||
header {
|
||||
background-image: url(https://images.unsplash.com/photo-1524413840807-0c3cb6fa808d?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format);
|
||||
background-position: center center;
|
||||
background-image: url(~/assets/pictues/header.avif);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-rose-500 hover:underline visited:bg-rose-700;
|
||||
}
|
||||
|
||||
.font-jetbrains {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
}
|
||||
|
||||
.font-rhd {
|
||||
font-family: 'Red Hat Display', sans-serif;
|
||||
code, kbd, pre, samp {
|
||||
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 {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
--tw-bg-opacity: 1;
|
||||
background: linear-gradient(transparent 150px,
|
||||
rgba(39, 39, 42, var(--tw-bg-opacity)));
|
||||
}
|
||||
|
||||
.love {
|
||||
text-decoration: underline;
|
||||
text-decoration-color: #EB0066;
|
||||
@@ -120,6 +142,7 @@ header {
|
||||
column-count: 12;
|
||||
}
|
||||
|
||||
.bg-grid-pink-600\/\[0\.05\] {
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' width='32' height='32' fill='none' stroke='rgb(90 43 136 / 0.05)'%3e%3cpath d='M0 .5H31.5V32'/%3e%3c/svg%3e");
|
||||
.btn-tabs {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(75px, max-content));
|
||||
}
|
||||
BIN
assets/pictues/header.avif
Normal file
|
After Width: | Height: | Size: 5.4 MiB |
BIN
assets/pictues/juls07.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
8
components/Nav.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<nav class="px-2 py-4">
|
||||
<ul class="flex gap-3 font-semibold">
|
||||
<li><nuxt-link class="text-white" to="/">Home</nuxt-link></li>
|
||||
<li><nuxt-link class="text-white" to="/blog">Blog</nuxt-link></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</template>
|
||||
33
components/TagButton.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
iconMap: {
|
||||
'nuxtjs': 'nuxt-icon',
|
||||
'nuxt': 'nuxt-icon',
|
||||
'nuxtjs-3': 'nuxt-icon',
|
||||
'web-dev': 'web-dev-icon',
|
||||
'fullstack-development': 'jamstack-icon',
|
||||
'angular': 'angular-icon',
|
||||
'nodejs': 'nodejs-icon',
|
||||
'mongodb': 'mongodb-icon',
|
||||
'docker': 'docker-icon',
|
||||
'linux': 'linux-tux',
|
||||
'bittorrent': 'webtorrent',
|
||||
'web-server': 'nginx'
|
||||
},
|
||||
}
|
||||
},
|
||||
props: ['iconName', 'name']
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button :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">
|
||||
<Icon size="20"
|
||||
class="mr-2"
|
||||
:name="('logos:' + (iconMap[iconName.toLowerCase().split(' ').join('-')] || iconName.toLowerCase()))" />
|
||||
{{name}}
|
||||
</button>
|
||||
</template>
|
||||
123
components/content/ProseCode.vue
Normal file
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div class="container my-2 bg-neutral-900">
|
||||
<span v-if="filename"
|
||||
class="filename-text text-xs leading-none tracking-tight text-gray-400 font-jetbrains">
|
||||
{{ filename }}
|
||||
</span>
|
||||
<slot />
|
||||
<div class="bottom-container">
|
||||
<div class="copy-container">
|
||||
<button class="rounded hover:bg-zinc-800/60 transition-colors duration-200 flex p-1"
|
||||
@click="copy(code)">
|
||||
<div class="h-6"
|
||||
v-if="copied">
|
||||
<Icon size="24" name="tabler:check" />
|
||||
</div>
|
||||
<div class="h-6"
|
||||
v-else>
|
||||
<Icon size="24" name="tabler:copy" />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
const { copy, copied, text } = useClipboard();
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
code?: string;
|
||||
language?: string | null;
|
||||
filename?: string | null;
|
||||
highlights?: Array<number>;
|
||||
}>(),
|
||||
{ code: '', language: null, filename: null, highlights: [] }
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.icon {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
padding-top: 0.5em;
|
||||
overflow: hidden;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.container:hover .bottom-container {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.bottom-container {
|
||||
display: flex;
|
||||
transition-property: opacity;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 250ms;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
position: relative;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.copy-container {
|
||||
height: fit-content;
|
||||
display: flex;
|
||||
position: absolute;
|
||||
bottom: 15px;
|
||||
right: 15px;
|
||||
}
|
||||
|
||||
.filename-text {
|
||||
position: absolute;
|
||||
top: 0.25rem;
|
||||
right: 0.25rem;
|
||||
padding: 0.25em 0.5em;
|
||||
}
|
||||
|
||||
:slotted(pre) {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
display: flex;
|
||||
flex: 1 1 0%;
|
||||
overflow-x: auto;
|
||||
padding: 1rem;
|
||||
line-height: 1.625;
|
||||
counter-reset: lines;
|
||||
}
|
||||
|
||||
:slotted(pre code) {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
:slotted(pre code .line) {
|
||||
min-height: 1em;
|
||||
}
|
||||
|
||||
:slotted(pre code .line::before) {
|
||||
counter-increment: lines;
|
||||
content: counter(lines);
|
||||
width: 1em;
|
||||
margin-right: 1.5rem;
|
||||
display: inline-block;
|
||||
text-align: right;
|
||||
color: rgba(115, 138, 148, 0.4);
|
||||
}
|
||||
|
||||
:slotted(pre code .highlight) {
|
||||
background-color: #363b46;
|
||||
display: block;
|
||||
margin-right: -1em;
|
||||
margin-left: -1em;
|
||||
padding-right: 1em;
|
||||
padding-left: 0.75em;
|
||||
border-left: 0.25em solid red;
|
||||
}
|
||||
</style>
|
||||
17
components/content/ProseCodeInline.vue
Normal file
@@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<code lang="js">
|
||||
<slot />
|
||||
</code>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
code {
|
||||
background-color: #252425;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem;
|
||||
overflow: hidden;
|
||||
padding: 3px 6px;
|
||||
}
|
||||
</style>
|
||||
41
components/content/ProseH2.vue
Normal file
@@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<div :id="id"
|
||||
class="group flex mt-2">
|
||||
<div class="text-2xl">
|
||||
<slot />
|
||||
</div>
|
||||
<button @click="copy(location.origin + location.pathname + '#' + id)"
|
||||
class="group-hover:opacity-100 ml-2 hover:bg-zinc-800 flex items-center h-fit p-[2px] transition-opacity duration-200 rounded opacity-0">
|
||||
<div class="h-4"
|
||||
v-if="copied">
|
||||
<Icon size="16"
|
||||
name="tabler:check" />
|
||||
</div>
|
||||
<div class="h-4"
|
||||
v-else>
|
||||
<Icon size="16"
|
||||
name="tabler:link" />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
useClipboard, useBrowserLocation
|
||||
} from '@vueuse/core';
|
||||
const { copy, copied, text } = useClipboard();
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
id?: string;
|
||||
}>(),
|
||||
{ id: '' }
|
||||
);
|
||||
const location = useBrowserLocation()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.icon {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
9
components/newsletterSignup.vue
Normal file
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<div class="bg-[#1f1d1f] px-4 py-4 md:py-6 rounded-lg border border-neutral-800 flex flex-col">
|
||||
<h1 class="mb-2 text-2xl">Get notified</h1>
|
||||
<input type="email"
|
||||
placeholder="Email..."
|
||||
name="email"
|
||||
class="px-4 py-2 my-2 w-full sm:w-4/5 border shadow-sm rounded-md resize-none border-neutral-700 transition-colors bg-zinc-800 focus:border-neutral-500 focus:outline-none placeholder:italic placeholder:text-gray-300 text-white" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,10 +1,10 @@
|
||||
<script>
|
||||
export default {
|
||||
props: ['iconSrc', 'name']
|
||||
props: ['iconName', 'name']
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<button class="font-inter md:text-lg w-fit min-w-fit bg-zinc-800 py-1 px-2 rounded shadow flex items-center"><img
|
||||
:src="iconSrc"
|
||||
class="mr-2 w-5 h-5" />{{name}}</button>
|
||||
<button :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">
|
||||
<Icon size="20" class="mr-2" :name="iconName" />
|
||||
{{name}}</button>
|
||||
</template>
|
||||
43
content/blog/how-i-made-my-site-fast.md
Normal file
@@ -0,0 +1,43 @@
|
||||
---
|
||||
title: How I made my site fast
|
||||
description: How I made my social media site fast
|
||||
img: /images/how-i-made-my-site-fast.png
|
||||
alt: how i made snowball fast
|
||||
writer: juls07
|
||||
date: 2022-05-22
|
||||
tags:
|
||||
- web dev
|
||||
- fullstack development
|
||||
- angular
|
||||
- nodejs
|
||||
- redis
|
||||
---
|
||||
So yesterday I talked about my social media site that I'm working on. Today I implemented redis, a memory store that I used to reduce requests at most by 48ms. First when I tried to use redis I just used the `redis` package off of npmjs because it only makes sense but when I tried to get a key with the name of `user-cache-[userId]` It failed for some reason, I still dont know why it failed but using the `ioredis` package and everything started working, not user data processing, what I used redis to cache since it's a terrible for loop that executes database requests for every post, but now it's all stored in memory. I still want to add TTL since my VPS that I intend on deploying my site on for production only has 1GB of RAM but I'm not sure how to do that. If you saw my blog post from [yesterday](/blog/what-ive-been-doing) then you'll know what my user code used to look like, now it looks like this.
|
||||
|
||||
```js[post.js]
|
||||
for (let i = 0; i < replies.length; i++) {
|
||||
await redisClient.get('cache-user-' + replies[i].creator, (err, reply) => {
|
||||
if (reply == null || err) {
|
||||
usermodel.findById(replies[i].creator, '-password -__v -email', async function(err, user) {
|
||||
if (err) {
|
||||
return res.status(500).json({
|
||||
message: "Fetching posts failed"
|
||||
});
|
||||
}
|
||||
replies[i].creator = user;
|
||||
redisClient.set('cache-user-' + replies[i].creator._id, JSON.stringify(user))
|
||||
})
|
||||
} else {
|
||||
replies[i].creator = JSON.parse(reply)
|
||||
}
|
||||
})
|
||||
if (i === replies.length - 1) {
|
||||
return res.status(200).json({
|
||||
message: "replies fetched successfully",
|
||||
replies: await replies
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With this you can see first it checks for the user data in cache if there is nonde then it will grab the data from mongodb and then write it to the redis cache. Next time, I want to cache replies and posts but I'm still worried about memory constraint on my VPS. After all of the redis caching I still want to speed up my site more, I want to replace JWT because I dont like it that much and I still want to find a workaround to Opengraph tags. After everything If you want to hear about it more often follow me on [@julie4055_](https://twitter.com/julie4055_), I'm also thinking about writing a blog daily-ish rather than just posting every other month or so, and that'll be it have a great rest of your day!
|
||||
74
content/blog/nuxtjs-trpc-fullstack.md
Normal file
@@ -0,0 +1,74 @@
|
||||
---
|
||||
title: My nuxtjs + trpc fullstack web app
|
||||
description: My experiences with nuxtjs 3 and tRPC
|
||||
img: /images/how-i-made-my-site-fast.png
|
||||
alt: how i made snowball fast
|
||||
writer: juls07
|
||||
date: 2022-09-20
|
||||
_draft: true
|
||||
tags:
|
||||
- web dev
|
||||
- fullstack development
|
||||
- nuxtjs 3
|
||||
- tRPC
|
||||
- redis
|
||||
---
|
||||
|
||||
Recently I've been working with nuxtjs 3 and tTRPC. I've heard a lot of things about nuxtjs 3 and tRPC lately, mostly bad with nuxtjs 3 and mostly good with trpc. These are not technoligies I've been interested in working with for a while
|
||||
|
||||
## JS Code Block
|
||||
|
||||
```js
|
||||
const a = 5;
|
||||
```
|
||||
|
||||
## One liners
|
||||
`here` `and here` `count` you don't even know what you're asking me to confess
|
||||
|
||||
## Vue Code Block
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<input v-model.lazy="message"/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { watch, ref } from 'vue'
|
||||
|
||||
const message = ref('');
|
||||
|
||||
const saveMessage = () => {
|
||||
// do anything with the message
|
||||
}
|
||||
|
||||
watch(message, (newMessage) => {
|
||||
saveMessage(newMessage) // only called on change events
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## Vue Code Block With Line Highlighting
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
{#if tags.length > 0}
|
||||
{#each tags as tag}
|
||||
<Tag {tag} />
|
||||
{/each}
|
||||
{:else}
|
||||
<p>This release has no tags</p>
|
||||
{/if}
|
||||
</script>
|
||||
```
|
||||
|
||||
```lua {2,6-10}
|
||||
local name = "juls07"
|
||||
```
|
||||
|
||||
## Vue Code Block With Filename
|
||||
|
||||
```vue [pages/[...slug.vue]]
|
||||
<template>
|
||||
<input v-model.lazy="message" />
|
||||
</template>
|
||||
```
|
||||
19
content/blog/running-bittorent-webserver.md
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: Running a qbittorrent webserver!
|
||||
description: My experience with a qbittorrent webserver
|
||||
img: /images/qbittorrent-web.png
|
||||
alt: running bittorrent webserver
|
||||
writer: juls07
|
||||
date: 2022-03-07
|
||||
tags:
|
||||
- Linux
|
||||
- Bittorrent
|
||||
- Docker
|
||||
- Web server
|
||||
---
|
||||
|
||||
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. 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"/>
|
||||
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"/>
|
||||
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!
|
||||
38
content/blog/what-ive-been-doing.md
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
title: What I've been doing
|
||||
description: Stuff I've been doing recently
|
||||
img: /images/what-ive-been-doing.png
|
||||
alt: what ive been doing
|
||||
writer: juls07
|
||||
date: 2022-05-21
|
||||
tags:
|
||||
- web dev
|
||||
- fullstack development
|
||||
- angular
|
||||
- nodejs
|
||||
- mongodb
|
||||
---
|
||||
|
||||
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. 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"/>
|
||||
I've gotten a VPS from [linode](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
|
||||
for (let i = 0; i < posts.length; i++) {
|
||||
usermodel.findById(posts[i].creator, '-password -__v -followers -following -email', async function (err, user) {
|
||||
if (err) {
|
||||
return res.status(500).json({
|
||||
message: "Fetching posts failed"
|
||||
});
|
||||
}
|
||||
posts[i].creator = user;
|
||||
if (i === posts.length - 1) {
|
||||
return res.status(200).json({
|
||||
message: "Posts fetched successfully",
|
||||
posts: await posts,
|
||||
maxPosts: await maxPosts
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
```
|
||||
seen here is the code to change the userId's in get `/api/posts` so making at most 15 database requests per request, maybe a caching solution like redis might be applicable but I have never used something like that but I think I will definitely deploy something like that for caching. After everything If you want to hear about it more often follow me on [@julie4055_](https://twitter.com/julie4055_) and that'll be it have a great rest of your day!
|
||||
18
content/blog/why-i-chose-arch.md
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
title: Why I chose archlinux
|
||||
description: All of my reasons for choosing archlinux
|
||||
img: /images/archlinux.png
|
||||
alt: why I chose arch
|
||||
writer: juls07
|
||||
date: 2022-03-07
|
||||
tags:
|
||||
- Linux
|
||||
- archlinux
|
||||
---
|
||||
|
||||
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. 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"/>
|
||||
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"/>
|
||||
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.
|
||||
@@ -1,10 +1,32 @@
|
||||
import { defineNuxtConfig } from 'nuxt/config';
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
target: 'static',
|
||||
|
||||
css: ['~/assets/css/main.css'],
|
||||
|
||||
postcss: {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
},
|
||||
|
||||
modules: ['nuxt-icon', '@nuxt/content'],
|
||||
|
||||
nitro: {
|
||||
prerender: {
|
||||
routes: ['/sitemap.xml']
|
||||
}
|
||||
},
|
||||
|
||||
content: {
|
||||
documentDriven: true,
|
||||
highlight: {
|
||||
theme: {
|
||||
default: 'github-dark'
|
||||
},
|
||||
preload: ['json', 'js', 'ts', 'html', 'css', 'vue', 'svelte', 'diff', 'shell', 'markdown', 'yaml', 'bash', 'ini'],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
3532
package-lock.json
generated
@@ -8,9 +8,13 @@
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/content": "^2.2.2",
|
||||
"@vueuse/core": "^9.6.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"nuxt": "3.0.0",
|
||||
"nuxt-icon": "^0.1.7",
|
||||
"postcss": "^8.4.19",
|
||||
"sitemap": "^7.1.1",
|
||||
"tailwindcss": "^3.2.4"
|
||||
}
|
||||
}
|
||||
|
||||
27
pages/blog/[...slug].vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<Nav />
|
||||
<main class="grid grid-cols-12 gap-5 justify-center">
|
||||
<div class="py-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 }">
|
||||
<img :src="doc.img" class="mb-2" />
|
||||
<h1 class="text-3xl md:text-4xl font-semibold mb-2">{{ doc.title }}</h1>
|
||||
<p class="mb-1 text-zinc-400">
|
||||
{{ doc.description }}
|
||||
</p>
|
||||
<p class="mb-2 text-zinc-600 dark:text-zinc-400">
|
||||
{{ new Date(doc.date).toDateString().split(' ').slice(1).join(' ') }}
|
||||
</p>
|
||||
<div class="flex flex-wrap w-full gap-2 justify-start mb-7">
|
||||
<tagButton v-for="tag in doc.tags" :name="tag"
|
||||
:iconName='tag' />
|
||||
</div>
|
||||
<ContentRenderer :value="doc" />
|
||||
</ContentDoc>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="grid grid-cols-12 gap-5 justify-center">
|
||||
<div class="py-6 mb-4 !col-start-3 md:!col-start-4 xl:!col-start-5 xl:col-span-4 md:col-span-6 col-span-8">
|
||||
<NewsletterSignup />
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
77
pages/blog/index.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div>
|
||||
<Nav />
|
||||
<div class="gap-4 justify-evenly grid grid-cols-[repeat(auto-fit,_minmax(50px,_450px))]">
|
||||
<div v-for="article in articles"
|
||||
:key="article._path"
|
||||
class="mb-5 px-1.5">
|
||||
<p v-show="false">{{ article.date }}</p>
|
||||
<div class="text-white rounded-lg border border-neutral-700 bg-zinc-800 shadow-md">
|
||||
<img v-if="article.img"
|
||||
:src="article.img"
|
||||
class="w-full rounded-tl-lg rounded-tr-lg" />
|
||||
<div class="p-3">
|
||||
<h3>
|
||||
<nuxt-link class="text-lg"
|
||||
:to="article._path">
|
||||
{{ article.title }}
|
||||
</nuxt-link>
|
||||
</h3>
|
||||
<p class="text-zinc-600 dark:text-zinc-500">
|
||||
{{ new Date(article.date).toDateString().split(' ').slice(1).join(' ') }}
|
||||
</p>
|
||||
<p class="text-zinc-400 dark:text-zinc-400">
|
||||
{{ article.description }}
|
||||
</p>
|
||||
<p style="max-height: 224px;"
|
||||
class="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-zinc-800 mb-1 pb-1 relative text-zinc-200">
|
||||
<ContentDoc :value="article" :path="article._path" v-slot="{ doc }">
|
||||
<div class="flex flex-wrap w-full gap-2 justify-start mb-2">
|
||||
<tagButton v-for="tag in doc.tags"
|
||||
:name="tag"
|
||||
:iconName='tag' />
|
||||
</div>
|
||||
<ContentRenderer :value="doc" />
|
||||
</ContentDoc>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const { data: articles } = await useAsyncData('posts-list', () => queryContent('/blog')
|
||||
.where({ _draft: false })
|
||||
.sort({ date: -1, $numeric: true, })
|
||||
.find()
|
||||
);
|
||||
</script>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
head: {
|
||||
title: "Juls07",
|
||||
htmlAttrs: {
|
||||
lang: "en",
|
||||
},
|
||||
meta: [
|
||||
{ charset: "utf-8" },
|
||||
{ name: "viewport", content: "width=device-width, initial-scale=1" },
|
||||
{ name: "google", content: "notranslate" },
|
||||
{
|
||||
hid: "description",
|
||||
name: "description",
|
||||
content: "Juls07 is a game developer, web developer and pixel artist.",
|
||||
},
|
||||
{ property: "og:type", content: "website" },
|
||||
{ property: "og:image", content: "/og.png" },
|
||||
{ property: "og:title", content: "Juls07" },
|
||||
{ property: "og:description", content: "Juls07's website" },
|
||||
{ property: "og:url", content: "https://juls07.dev" },
|
||||
],
|
||||
link: [{ rel: "icon", type: "image/x-icon", href: "/favicon.ico" }],
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,11 +1,12 @@
|
||||
<template>
|
||||
<div class="h-screen text-white">
|
||||
<header class="w-screen h-3/5 sm:h-2/5 md:h-3/5">
|
||||
<Nav class="absolute z-10" />
|
||||
<header class="w-screen h-3/6 sm:h-2/5 md:h-3/5">
|
||||
<div
|
||||
class="p-6 bg-[#12121233] justify-center grid sm:grid-cols-12 gap-5 items-center sm:justify-start w-full h-full backdrop-blur-md backdrop-saturate-[1.15]">
|
||||
<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">
|
||||
<img src="https://avatars.githubusercontent.com/u/62722391"
|
||||
<img src="~/assets/pictues/juls07.png"
|
||||
class="h-32 md:h-40 max-h-full rounded-full mb-3 sm:mb-0 sm:mr-2" />
|
||||
<div class="grid grid-rows-5 grid-cols-1 h-fit">
|
||||
<h1 class="text-4xl md:text-5xl row-span-3 font-jetbrains">Juls07</h1>
|
||||
@@ -14,30 +15,56 @@
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<main
|
||||
class="grid grid-cols-12 inset-0 bg-grid-slate-900/[0.04] bg-grid-pink-600/[0.05] bg-bottom border-[#2d1544]/5 gap-5 justify-center">
|
||||
<main class="grid grid-cols-12 gap-5 justify-center">
|
||||
<section
|
||||
class="py-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">
|
||||
<h2 class="text-rhd md:text-4xl text-3xl mb-1">About me</h2>
|
||||
<h2 class="md:text-4xl text-3xl mb-1">About me</h2>
|
||||
<hr class="border-2 border-[#EB0066] rounded-md w-7/12 min-w-[200px] max-w-xs lg:max-w-sm mb-1" />
|
||||
<p class="max-w-md sm:max-w-xl md:max-w-3xl lg:max-w-4xl mb-3">
|
||||
Hi there, I'm juls07, I am 14 years old and I <span tabindex="1" class="love">love</span> web
|
||||
<p class="max-w-md sm:max-w-xl md:max-w-3xl lg:max-w-4xl mb-4">
|
||||
Hi there, I'm juls07, I am 14 years old and I <span tabindex="1"
|
||||
class="love">love</span> web
|
||||
development. I first dabbled in web development
|
||||
when I was ten, and here we are today! I mainly use
|
||||
<a class="text-rose-500 hover:underline visited:bg-rose-700" href="https://nuxtjs.org">NuxtJs</a> to
|
||||
<a
|
||||
href="https://nuxtjs.org">NuxtJs</a> to
|
||||
build my websites since I absolutely
|
||||
adore Vuejs. For me, I love being able to imagine anything and it to come to life. Finally, go
|
||||
checkout my <a class="text-rose-500 hover:underline visited:bg-rose-700"
|
||||
checkout my <a
|
||||
href="https://github.com/juls0730">Github</a> and also my <a
|
||||
class="text-rose-500 hover:underline visited:bg-rose-700"
|
||||
href="https://twitter.com/julie4055_">Twitter</a>.
|
||||
</p>
|
||||
<h3 class="text-rhd text-2xl md:text-3xl mb-1">Skills</h3>
|
||||
<section class="grid grid-flow-col gap-2 justify-start">
|
||||
<SkillButton name="javascript" iconSrc='/icons/JavaScript.svg' />
|
||||
<SkillButton name="Vue.js" iconSrc="/icons/Vue.js.svg" />
|
||||
<SkillButton name="Ruby on rails" iconSrc="/icons/ruby.svg" />
|
||||
<SkillButton name="php" iconSrc="/icons/Laravel.svg" />
|
||||
<h3 class="text-2xl md:text-3xl mb-1">Skills</h3>
|
||||
<section class="flex flex-wrap w-full gap-2 justify-start">
|
||||
<SkillButton name="Javascript"
|
||||
iconName='logos:javascript' />
|
||||
<SkillButton name="Nuxt.js"
|
||||
iconName="logos:nuxt-icon" />
|
||||
<SkillButton name="Ruby on rails"
|
||||
iconName="logos:ruby" />
|
||||
<SkillButton name="php"
|
||||
iconName="logos:laravel" />
|
||||
<SkillButton name="Angular"
|
||||
iconName="logos:angular-icon" />
|
||||
<SkillButton name="React"
|
||||
iconName="logos:react" />
|
||||
<SkillButton name="Bash"
|
||||
iconName="logos:bash-icon" />
|
||||
<SkillButton name="Tailwindcss"
|
||||
iconName="logos:tailwindcss-icon" />
|
||||
<SkillButton name="Rust"
|
||||
iconName="logos:rust" />
|
||||
<SkillButton name="Node.js"
|
||||
iconName="logos:nodejs-icon" />
|
||||
<SkillButton name="Svelte"
|
||||
iconName="logos:svelte-icon" />
|
||||
<SkillButton name="Supabase"
|
||||
iconName="logos:supabase-icon" />
|
||||
<SkillButton name="tRPC"
|
||||
iconName="logos:trpc" />
|
||||
<SkillButton name="Python"
|
||||
iconName="logos:python" />
|
||||
<SkillButton name="Deno"
|
||||
iconName="logos:deno" />
|
||||
</section>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="1052.000000pt" height="1052.000000pt" viewBox="0 0 1052.000000 1052.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
|
||||
<rect width="1052.000000pt" height="1052.000000pt" fill="#f0db4f" />
|
||||
<g transform="translate(0.000000,1052.000000) scale(0.100000,-0.100000)"
|
||||
fill="#323330" stroke="none">
|
||||
<path d="M7845 5740 c-375 -28 -699 -165 -930 -395 -249 -247 -365 -538 -365
|
||||
-914 0 -558 230 -948 740 -1256 128 -77 304 -161 615 -295 297 -128 428 -192
|
||||
536 -261 146 -94 228 -211 248 -355 37 -261 -140 -470 -455 -535 -137 -29
|
||||
-355 -23 -494 14 -254 66 -452 216 -627 474 -31 46 -60 83 -64 83 -9 0 -770
|
||||
-439 -786 -454 -10 -9 -2 -30 37 -94 302 -509 785 -814 1415 -897 173 -23 477
|
||||
-23 645 -1 402 54 710 190 947 419 205 198 325 447 363 751 16 121 8 375 -15
|
||||
499 -47 257 -160 474 -343 661 -211 215 -487 379 -1033 614 -412 177 -550 253
|
||||
-641 350 -87 93 -124 202 -116 338 7 108 37 181 103 252 95 103 205 146 375
|
||||
145 194 0 316 -49 445 -178 45 -44 103 -115 130 -158 27 -43 54 -76 61 -73 11
|
||||
4 745 473 753 482 7 7 -104 174 -170 257 -262 327 -600 493 -1069 526 -156 12
|
||||
-156 12 -305 1z"/>
|
||||
<path d="M4727 3923 l-3 -1768 -22 -83 c-68 -254 -207 -353 -496 -354 -255 -1
|
||||
-411 108 -589 414 -29 48 -55 87 -58 86 -4 -2 -185 -111 -402 -243 l-395 -239
|
||||
33 -66 c178 -353 487 -621 859 -745 354 -118 832 -120 1180 -3 504 168 799
|
||||
558 866 1143 6 58 10 712 10 1858 l0 1767 -490 0 -489 0 -4 -1767z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1 +0,0 @@
|
||||
<svg width="50" height="52" viewBox="0 0 50 52" xmlns="http://www.w3.org/2000/svg"><title>Logomark</title><path d="M49.626 11.564a.809.809 0 0 1 .028.209v10.972a.8.8 0 0 1-.402.694l-9.209 5.302V39.25c0 .286-.152.55-.4.694L20.42 51.01c-.044.025-.092.041-.14.058-.018.006-.035.017-.054.022a.805.805 0 0 1-.41 0c-.022-.006-.042-.018-.063-.026-.044-.016-.09-.03-.132-.054L.402 39.944A.801.801 0 0 1 0 39.25V6.334c0-.072.01-.142.028-.21.006-.023.02-.044.028-.067.015-.042.029-.085.051-.124.015-.026.037-.047.055-.071.023-.032.044-.065.071-.093.023-.023.053-.04.079-.06.029-.024.055-.05.088-.069h.001l9.61-5.533a.802.802 0 0 1 .8 0l9.61 5.533h.002c.032.02.059.045.088.068.026.02.055.038.078.06.028.029.048.062.072.094.017.024.04.045.054.071.023.04.036.082.052.124.008.023.022.044.028.068a.809.809 0 0 1 .028.209v20.559l8.008-4.611v-10.51c0-.07.01-.141.028-.208.007-.024.02-.045.028-.068.016-.042.03-.085.052-.124.015-.026.037-.047.054-.071.024-.032.044-.065.072-.093.023-.023.052-.04.078-.06.03-.024.056-.05.088-.069h.001l9.611-5.533a.801.801 0 0 1 .8 0l9.61 5.533c.034.02.06.045.09.068.025.02.054.038.077.06.028.029.048.062.072.094.018.024.04.045.054.071.023.039.036.082.052.124.009.023.022.044.028.068zm-1.574 10.718v-9.124l-3.363 1.936-4.646 2.675v9.124l8.01-4.611zm-9.61 16.505v-9.13l-4.57 2.61-13.05 7.448v9.216l17.62-10.144zM1.602 7.719v31.068L19.22 48.93v-9.214l-9.204-5.209-.003-.002-.004-.002c-.031-.018-.057-.044-.086-.066-.025-.02-.054-.036-.076-.058l-.002-.003c-.026-.025-.044-.056-.066-.084-.02-.027-.044-.05-.06-.078l-.001-.003c-.018-.03-.029-.066-.042-.1-.013-.03-.03-.058-.038-.09v-.001c-.01-.038-.012-.078-.016-.117-.004-.03-.012-.06-.012-.09v-.002-21.481L4.965 9.654 1.602 7.72zm8.81-5.994L2.405 6.334l8.005 4.609 8.006-4.61-8.006-4.608zm4.164 28.764l4.645-2.674V7.719l-3.363 1.936-4.646 2.675v20.096l3.364-1.937zM39.243 7.164l-8.006 4.609 8.006 4.609 8.005-4.61-8.005-4.608zm-.801 10.605l-4.646-2.675-3.363-1.936v9.124l4.645 2.674 3.364 1.937v-9.124zM20.02 38.33l11.743-6.704 5.87-3.35-8-4.606-9.211 5.303-8.395 4.833 7.993 4.524z" fill="#FF2D20" fill-rule="evenodd"/></svg>
|
||||
|
Before Width: | Height: | Size: 2.0 KiB |
@@ -1,9 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-11.5 -10.23174 23 20.46348">
|
||||
<title>React Logo</title>
|
||||
<circle cx="0" cy="0" r="2.05" fill="#61dafb"/>
|
||||
<g stroke="#61dafb" stroke-width="1" fill="none">
|
||||
<ellipse rx="11" ry="4.2"/>
|
||||
<ellipse rx="11" ry="4.2" transform="rotate(60)"/>
|
||||
<ellipse rx="11" ry="4.2" transform="rotate(120)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 365 B |
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" viewBox="0 0 261.76 226.69" xmlns="http://www.w3.org/2000/svg"><g transform="matrix(1.3333 0 0 -1.3333 -76.311 313.34)"><g transform="translate(178.06 235.01)"><path d="m0 0-22.669-39.264-22.669 39.264h-75.491l98.16-170.02 98.16 170.02z" fill="#41b883"/></g><g transform="translate(178.06 235.01)"><path d="m0 0-22.669-39.264-22.669 39.264h-36.227l58.896-102.01 58.896 102.01z" fill="#34495e"/></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 466 B |
|
Before Width: | Height: | Size: 19 KiB |
BIN
public/images/archlinux.png
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
public/images/how-i-made-my-site-fast.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
public/images/qbittorrent-web.png
Normal file
|
After Width: | Height: | Size: 431 KiB |
BIN
public/images/what-ive-been-doing.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
19
server/routes/sitemap.xml.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { serverQueryContent } from '#content/server'
|
||||
import { SitemapStream, streamToPromise } from 'sitemap'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
// Fetch all documents
|
||||
const docs = await serverQueryContent(event).find()
|
||||
const sitemap = new SitemapStream({
|
||||
hostname: 'https://juls07.dev'
|
||||
})
|
||||
|
||||
for (const doc of docs) {
|
||||
sitemap.write({
|
||||
url: doc._path
|
||||
})
|
||||
}
|
||||
sitemap.end()
|
||||
|
||||
return streamToPromise(sitemap)
|
||||
})
|
||||
3
supabase/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Supabase
|
||||
.branches
|
||||
.temp
|
||||
71
supabase/config.toml
Normal file
@@ -0,0 +1,71 @@
|
||||
# A string used to distinguish different Supabase projects on the same host. Defaults to the working
|
||||
# directory name when running `supabase init`.
|
||||
project_id = "juls07.dev-rebuild"
|
||||
|
||||
[api]
|
||||
# Port to use for the API URL.
|
||||
port = 54321
|
||||
# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API
|
||||
# endpoints. public and storage are always included.
|
||||
schemas = []
|
||||
# Extra schemas to add to the search_path of every request.
|
||||
extra_search_path = ["extensions"]
|
||||
# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size
|
||||
# for accidental or malicious requests.
|
||||
max_rows = 1000
|
||||
|
||||
[db]
|
||||
# Port to use for the local database URL.
|
||||
port = 54322
|
||||
# The database major version to use. This has to be the same as your remote database's. Run `SHOW
|
||||
# server_version;` on the remote database to check.
|
||||
major_version = 14
|
||||
|
||||
[studio]
|
||||
# Port to use for Supabase Studio.
|
||||
port = 54323
|
||||
|
||||
# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they
|
||||
# are monitored, and you can view the emails that would have been sent from the web interface.
|
||||
[inbucket]
|
||||
# Port to use for the email testing server web interface.
|
||||
port = 54324
|
||||
smtp_port = 54325
|
||||
pop3_port = 54326
|
||||
|
||||
[storage]
|
||||
# The maximum file size allowed (e.g. "5MB", "500KB").
|
||||
file_size_limit = "50MiB"
|
||||
|
||||
[auth]
|
||||
# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
|
||||
# in emails.
|
||||
site_url = "http://localhost:3000"
|
||||
# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
|
||||
additional_redirect_urls = ["https://localhost:3000"]
|
||||
# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 seconds (one
|
||||
# week).
|
||||
jwt_expiry = 3600
|
||||
# Allow/disallow new user signups to your project.
|
||||
enable_signup = true
|
||||
|
||||
[auth.email]
|
||||
# Allow/disallow new user signups via email to your project.
|
||||
enable_signup = true
|
||||
# If enabled, a user will be required to confirm any email change on both the old, and new email
|
||||
# addresses. If disabled, only the new email is required to confirm.
|
||||
double_confirm_changes = true
|
||||
# If enabled, users need to confirm their email address before signing in.
|
||||
enable_confirmations = false
|
||||
|
||||
# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`,
|
||||
# `discord`, `facebook`, `github`, `gitlab`, `google`, `twitch`, `twitter`, `slack`, `spotify`.
|
||||
[auth.external.apple]
|
||||
enabled = false
|
||||
client_id = ""
|
||||
secret = ""
|
||||
# Overrides the default auth redirectUrl.
|
||||
redirect_uri = ""
|
||||
# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure,
|
||||
# or any other third-party OIDC providers.
|
||||
url = ""
|
||||
@@ -3,15 +3,30 @@
|
||||
// This enables autocomplete, go to definition, etc.
|
||||
|
||||
import { serve } from "https://deno.land/std@0.131.0/http/server.ts"
|
||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
|
||||
|
||||
console.log("Hello from Functions!")
|
||||
console.log("Hello from functions!")
|
||||
const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
|
||||
serve(async (req) => {
|
||||
const { name } = await req.json()
|
||||
const data = {
|
||||
message: `Hello ${name}!`,
|
||||
if (req.method === 'OPTIONS') {
|
||||
return new Response('ok')
|
||||
}
|
||||
|
||||
const supabase = createClient(Deno.env.get('SUPABASE_URL'), Deno.env.get('SUPABASE_ANON_KEY'))
|
||||
|
||||
const { email, name } = await req.json()
|
||||
if (!name || !email || !emailRegex.test(email)) throw new Error(
|
||||
'Please provide a valid email address or name'
|
||||
)
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('subscribers')
|
||||
.upsert({ name: name, email: email })
|
||||
.select()
|
||||
|
||||
if (error) throw new Error(error.message)
|
||||
|
||||
return new Response(
|
||||
JSON.stringify(data),
|
||||
{ headers: { "Content-Type": "application/json" } },
|
||||
|
||||
0
supabase/seed.sql
Normal file
@@ -4,6 +4,7 @@ module.exports = {
|
||||
"./components/**/*.{js,vue,ts}",
|
||||
"./layouts/**/*.vue",
|
||||
"./pages/**/*.vue",
|
||||
"./content/**/*.mdc",
|
||||
"./plugins/**/*.{js,ts}",
|
||||
"./nuxt.config.{js,ts}",
|
||||
"./app.vue",
|
||||
|
||||