Compare commits

..
6 Commits
Author SHA1 Message Date
Riyyi 74d571c10f Put all binaries in git 2025-04-09 00:02:54 +02:00
Riyyi 9bbbb80e75 Implement sitemap.xml and robots.txt 2025-04-08 23:36:17 +02:00
Riyyi f610edf22c Prepend baseURL to favicon.ico 2025-04-07 20:35:53 +02:00
Riyyi 5aa314e40e Finish blaze lisp article 2025-04-07 19:59:24 +02:00
Riyyi 07fde286c4 Add two more programming articles 2025-04-06 23:02:54 +02:00
Riyyi d76464d4f3 Finish utility library article 2025-04-06 21:47:13 +02:00
23 changed files with 546 additions and 33 deletions
+11 -8
View File
@@ -1,18 +1,21 @@
import { defineContentConfig, defineCollection, z } from '@nuxt/content'
import { asSitemapCollection } from "@nuxtjs/sitemap/content"
// Lookup resolved from path: rootDir/content
// see: https://github.com/nuxt/content/issues/3161
export default defineContentConfig({
collections: {
content: defineCollection({
type: "page",
source: "**/*.md",
schema: z.object({
date: z.date(),
img: z.string(),
tags: z.array(z.string()),
content: defineCollection(
asSitemapCollection({
type: "page",
source: "**/*.md",
schema: z.object({
date: z.date(),
img: z.string(),
tags: z.array(z.string()),
})
})
})
)
}
});
+1 -1
View File
@@ -25,7 +25,7 @@ for the presentation that I gave at Hogeschool Rotterdam.
Korte video waarin de meeste functionaliteit van de bank ATM wordt getoond.
::VideoLazy{:src="https://riyyi.com/media/bank-atm-demo.webm"}
::VideoLazy{:src="/img/bank-atm/demo.webm"}
::
## Overzicht componenten
+93
View File
@@ -0,0 +1,93 @@
---
title: "blaze lisp"
description: "An implementation of the MAL (Make a Lisp) project."
navigation: false
date: "2023-03-18"
img: "/img/mal-steps.png"
tags:
- C++20
- CMake
- Software
---
<small>An implementation of the MAL (Make a Lisp) project.<br>
Repository at
[GitHub](https://github.com/riyyi/blaze){target="_blank"},
[GitLab](https://gitlab.com/riyyi/blaze){target="_blank"} or
[Gitea](https://git.riyyi.com/riyyi/blaze){target="_blank"}.
</small>
After having implemented the JSON serializer for my [utility
library](/articles/utility-library), I became interested in interpreters. The
utility library just has the `tokenization` step of an interpreter, so my tought
was, what's next? That's right, `parsing`.
Having used Emacs quite a bit, I wasn't shy of Lisp. Then, I came across the MAL
([Make a Lisp](https://github.com/kanaka/mal){target="_blank"}) project, and
decided to look into it. The project lays out the implementation steps of making
a Lisp programming language in 10 or so steps and also provides you with unit
tests that have to pass to proceed to the next step. There are also a bunch of
reference implementations to refer to, in case you get stuck.
Feeling like implementing a fully interpreted language was a bit of an
undertaking and realizing that in a Lisp `parsing` and `interpreting` is
basically combined into one step, it seemed achievable and I decided to give the
MAL project a go.
The final architechture that has to be implemented is pictured below.
<div class="row">
<div class="col-lg-9 col-xl-6">
![](/img/mal-steps.png "")
</div>
</div>
I managed to do a full implementation, including `variables`, `if` statements,
`loops`, `functions`, `try/catch` exceptions, `lists`, `arrays`, `hash-maps` and
even `macros`.
With the REPL you can try things out and play around easily.
```
./repl
Blaze [C++]
user>
```
```elisp
user> 123
123
user> (+ 1 2.5)
3.5
user> (- 10 (- 5 3))
8
user> "hello world"
"hello world"
user> (= 2 3)
true
user> (if (> 2 4) "yes" "no")
"no"
user> (count (list 3 6 2 9))
4
user> (count '(3 6 2 9)) ; list shorthand
4
user> (list? [2.1 nil "text"]) ; array / vector
false
user> {:a (+ 7 8)} ; hash-map
{"a" 15}
user> (def! mul (fn* [x y] (* x y))) ; defining a function
#<user-function>(0x5f35f38815d0)
user> (mul 4 5)
20
```
This project was really interesting and the language is quite powerful, powerful
enough to accomplish self-hosting! This means that an interpreter (or rather,
eval+apply) _for_ this language, can be written _in_ the language.
If you're curious about reading more examples, a good place is probably the
testsuite for the project, those have a bunch of unit tests and are available
[here](https://github.com/kanaka/mal/tree/master/impls/tests).
+33
View File
@@ -0,0 +1,33 @@
---
title: "GarbAGE (Garbage Accurate GameBoy Emulator)"
description: "GameBoy Emulator that is not that accurate."
navigation: false
date: "2022-08-17"
img: "/img/garbage.png"
tags:
- C++20
- CMake
- Software
---
<small>GarbAGE (Garbage Accurate GameBoy Emulator).<br>
Repository at
[GitHub](https://github.com/riyyi/garbage){target="_blank"},
[GitLab](https://gitlab.com/riyyi/garbage){target="_blank"} or
[Gitea](https://git.riyyi.com/riyyi/garbage){target="_blank"}.
</small>
This is an exploration into emulators by me and a friend of mine. The only thing
thats really implemented are the CPU opcodes. The cool thing however, is that
for the rendering portion of the application we are using my own
[game engine](/articles/inferno)! No other libraries were used.
The simplest game to test is Dr. Mario and even that one doesnt render
correctly, but we do get graphics that you can make out, pretty cool!
![garbage](/img/garbage.png "garbage")
Preview video of the boot sequence and intro of the Dr. Mario game.
::VideoLazy{:src="/img/garbage-preview.webm"}
::
+1 -1
View File
@@ -32,5 +32,5 @@ Preview.
Demo showcasing translation, rotation, scaling and textures working. You can
also fly around, which is not shown in the video.
::VideoLazy{:src="https://riyyi.com/media/opengl-test-demo.webm"}
::VideoLazy{:src="/img/opengl-test-demo.webm"}
::
+1 -1
View File
@@ -76,5 +76,5 @@ Completed assembly.
Domoticz is used as a controller, which completes the smart outlet project. View
the demo below.
::VideoLazy{:src="https://riyyi.com/media/smart-outlet-demo.webm"}
::VideoLazy{:src="/img/smart-outlet/demo.webm"}
::
+119 -2
View File
@@ -24,11 +24,128 @@ my projects and create one cohesive style.
## Argument parsing
placeholder
This is a simple argument parsing feature, with the attempt of making it simpler
to use than getopt. All you have to do is specify the variables you want to use,
then add the options and arguments on the `ArgParser` object and finally call
the `parse` function.
```cpp
#include <string>
#include <vector>
#include "ruc/argparser.h"
int main(int argc, const char* argv[])
{
bool verbose = false;
std::vector<std::string> targets {};
ruc::ArgParser argParser;
argParser.addOption(verbose, 'v', "verbose", nullptr, nullptr);
argParser.addArgument(targets, "targets", nullptr, nullptr, ruc::ArgParser::Required::No);
argParser.parse(argc, argv);
// Do some work here..
return 0;
}
```
The `nullptr`'s in the above example were going to be used for automatic help
string generation, but that isn't implemented yet.
## Formatting library
placeholder
This is basically a partial copy of the `fmt` library, from before that became
part of the C++20 standard and I didn't want to use an additional dependency in
my projects, because that is less fun!
The part of `fmt` that is implement is the
"[mini-language](https://fmt.dev/11.1/syntax/#format-specification-mini-language)",
which is a very convenient API.
```cpp
#include <string>
#include "ruc/format/format.h"
#include "ruc/format/print.h"
int main(int argc, const char* argv[])
{
std::string fmt = format(
R"(
number {}
string {}
bool {}j
double {}
double {:.2} with 2 precision
)", 123, "this is a string", true, 456.789, 3.14159265359);
print("{}\n", fmt);
return 0;
}
```
Which results the the output.
```
number 123
string this is a string
bool true
double 456.789000
double 3.14 with 2 precision
```
The implementation consists of 2 major parts, the parsing of the format string
and the `format` and `print` functions. The parsing part isn't that complex, so
wont be discussed here. The other secion is interesting, however.
The functions are implemented with variadic arguments using type erasure, this
improves both compile time and binary size significantly. What it also does, is
allow the library to work on types that are specified by the user and are
therefor not part of the library.
The formatter implements all the primitives and some of the STL types, it can be
extended by the user. The basic use-case is to specify to just the `format`
function, but the `parser` function can also be overwritten.
```cpp
// In the header we are extending the existing formatter for vectors,
// so we take advantage of their nice formatting automatically
template<>
struct ruc::format::Formatter<glm::vec4> : Formatter<std::vector<float>> {
void format(Builder& builder, glm::vec4 value) const;
};
// Then in the implementation, we implement the format functon
void ruc::format::Formatter<glm::vec4>::format(Builder& builder, glm::vec4 value) const
{
return Formatter<std::vector<float>>::format(builder, { value.x, value.y, value.z, value.w });
}
```
Users can even extend formatters based on their own formats. In this example we
are extending the vector (`glm::vec4`) formatter, so we can also print matrices
(`glm::mat4`).
```cpp
template<>
struct ruc::format::Formatter<glm::mat4> : Formatter<glm::vec4> {
void format(Builder& builder, glm::mat4 value) const;
};
void ruc::format::Formatter<glm::mat4>::format(Builder& builder, glm::mat4 value) const
{
builder.putString("mat4 ");
Formatter<glm::vec4>::format(builder, value[0]);
builder.putString("\n ");
Formatter<glm::vec4>::format(builder, value[1]);
builder.putString("\n ");
Formatter<glm::vec4>::format(builder, value[2]);
builder.putString("\n ");
return Formatter<glm::vec4>::format(builder, value[3]);
}
```
## JSON parsing
+9 -2
View File
@@ -15,7 +15,7 @@ export default defineNuxtConfig({
},
langs: [
// https://github.com/shikijs/shiki/blob/main/packages/langs/package.json
"c", "cpp", "css", "html", "js", "json", "lua", "md", "mdc", "php", "python", "shell", "ts", "vue", "yaml"
"c", "cpp", "css", "elisp", "html", "js", "json", "lua", "md", "mdc", "php", "python", "shell", "ts", "vue", "yaml"
]
},
toc: {
@@ -36,7 +36,9 @@ export default defineNuxtConfig({
public: "../public"
},
modules: [
"@nuxt/content",
"@nuxtjs/robots",
"@nuxtjs/sitemap",
"@nuxt/content", // NOTE: @nuxt/content after robots and sitemap
"@nuxt/eslint",
"@pinia/nuxt",
"pinia-plugin-persistedstate/nuxt",
@@ -52,6 +54,11 @@ export default defineNuxtConfig({
secure: process.env.NODE_ENV !== "development" // only send over HTTPS
}
},
routeRules: {
// Dont add to the sitemap.xml
"/__nuxt_content/**": { robots: false },
},
site: { url: "https://riyyi.com", name: "Personal Website" },
srcDir: "src/",
ssr: false,
typescript: {
+268 -1
View File
@@ -22,6 +22,8 @@
"@iconify-json/fa-solid": "^1.2.1",
"@nuxt/content": "^3.4.0",
"@nuxt/eslint": "^1.2.0",
"@nuxtjs/robots": "^5.2.9",
"@nuxtjs/sitemap": "^7.2.10",
"@types/bootstrap": "^5.2.10",
"@vue/language-server": "^2.1.10",
"@vue/typescript-plugin": "^2.1.10",
@@ -1642,6 +1644,136 @@
"vfile": "^6.0.3"
}
},
"node_modules/@nuxtjs/robots": {
"version": "5.2.9",
"resolved": "https://registry.npmjs.org/@nuxtjs/robots/-/robots-5.2.9.tgz",
"integrity": "sha512-JJykE1llIByw8vqhrn4abSPyAcEFnfVOkIaD2/XLwkhNeZHzAQT2/p+ZhqwtaSMyWq8pnW1y0ei7gQYdCqOu+g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nuxt/kit": "^3.16.2",
"consola": "^3.4.2",
"defu": "^6.1.4",
"nuxt-site-config": "^3.1.9",
"pathe": "^2.0.3",
"pkg-types": "^2.1.0",
"sirv": "^3.0.1",
"std-env": "^3.9.0",
"ufo": "^1.5.4"
},
"funding": {
"url": "https://github.com/sponsors/harlan-zw"
}
},
"node_modules/@nuxtjs/robots/node_modules/@nuxt/kit": {
"version": "3.16.2",
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.16.2.tgz",
"integrity": "sha512-K1SAUo2vweTfudKZzjKsZ5YJoxPLTspR5qz5+G61xtZreLpsdpDYfBseqsIAl5VFLJuszeRpWQ01jP9LfQ6Ksw==",
"dev": true,
"license": "MIT",
"dependencies": {
"c12": "^3.0.2",
"consola": "^3.4.2",
"defu": "^6.1.4",
"destr": "^2.0.3",
"errx": "^0.1.0",
"exsolve": "^1.0.4",
"globby": "^14.1.0",
"ignore": "^7.0.3",
"jiti": "^2.4.2",
"klona": "^2.0.6",
"knitwork": "^1.2.0",
"mlly": "^1.7.4",
"ohash": "^2.0.11",
"pathe": "^2.0.3",
"pkg-types": "^2.1.0",
"scule": "^1.3.0",
"semver": "^7.7.1",
"std-env": "^3.8.1",
"ufo": "^1.5.4",
"unctx": "^2.4.1",
"unimport": "^4.1.3",
"untyped": "^2.0.0"
},
"engines": {
"node": ">=18.12.0"
}
},
"node_modules/@nuxtjs/sitemap": {
"version": "7.2.10",
"resolved": "https://registry.npmjs.org/@nuxtjs/sitemap/-/sitemap-7.2.10.tgz",
"integrity": "sha512-7w1Ys2XIE/QVTJn5dbt2p/hrmDoGO9Ay1S3o6LI5M/MDRzKPvnXi5ByRUcc7Sfa3LUpLad5/w4IOQ4lyxhq9Hw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nuxt/devtools-kit": "^2.3.2",
"@nuxt/kit": "^3.16.2",
"chalk": "^5.4.1",
"defu": "^6.1.4",
"h3-compression": "^0.3.2",
"nuxt-site-config": "^3.1.9",
"ofetch": "^1.4.1",
"pathe": "^2.0.3",
"pkg-types": "^2.1.0",
"radix3": "^1.1.2",
"semver": "^7.7.1",
"sirv": "^3.0.1",
"ufo": "^1.5.4"
},
"engines": {
"node": ">=18.0.0"
},
"funding": {
"url": "https://github.com/sponsors/harlan-zw"
}
},
"node_modules/@nuxtjs/sitemap/node_modules/@nuxt/kit": {
"version": "3.16.2",
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.16.2.tgz",
"integrity": "sha512-K1SAUo2vweTfudKZzjKsZ5YJoxPLTspR5qz5+G61xtZreLpsdpDYfBseqsIAl5VFLJuszeRpWQ01jP9LfQ6Ksw==",
"dev": true,
"license": "MIT",
"dependencies": {
"c12": "^3.0.2",
"consola": "^3.4.2",
"defu": "^6.1.4",
"destr": "^2.0.3",
"errx": "^0.1.0",
"exsolve": "^1.0.4",
"globby": "^14.1.0",
"ignore": "^7.0.3",
"jiti": "^2.4.2",
"klona": "^2.0.6",
"knitwork": "^1.2.0",
"mlly": "^1.7.4",
"ohash": "^2.0.11",
"pathe": "^2.0.3",
"pkg-types": "^2.1.0",
"scule": "^1.3.0",
"semver": "^7.7.1",
"std-env": "^3.8.1",
"ufo": "^1.5.4",
"unctx": "^2.4.1",
"unimport": "^4.1.3",
"untyped": "^2.0.0"
},
"engines": {
"node": ">=18.12.0"
}
},
"node_modules/@nuxtjs/sitemap/node_modules/chalk": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
"integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/@oxc-parser/binding-linux-x64-gnu": {
"version": "0.56.5",
"cpu": [
@@ -5873,6 +6005,19 @@
"uncrypto": "^0.1.3"
}
},
"node_modules/h3-compression": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/h3-compression/-/h3-compression-0.3.2.tgz",
"integrity": "sha512-B+yCKyDRnO0BXSfjAP4tCXJgJwmnKp3GyH5Yh66mY9KuOCrrGQSPk/gBFG2TgH7OyB/6mvqNZ1X0XNVuy0qRsw==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/codedredd"
},
"peerDependencies": {
"h3": "^1.6.0"
}
},
"node_modules/h3/node_modules/cookie-es": {
"version": "1.2.2",
"dev": true,
@@ -8425,6 +8570,110 @@
"nuxt-component-meta": "bin/nuxt-component-meta.mjs"
}
},
"node_modules/nuxt-site-config": {
"version": "3.1.9",
"resolved": "https://registry.npmjs.org/nuxt-site-config/-/nuxt-site-config-3.1.9.tgz",
"integrity": "sha512-YB69GX0st8drv1d5xypweseiEWeR22tfGdyVH3U4R+mpUSz8paBx48ArKC6MgV22DKItoQm51LVoapF5pl5bEQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nuxt/kit": "^3.16.2",
"nuxt-site-config-kit": "3.1.9",
"pathe": "^2.0.3",
"pkg-types": "^2.1.0",
"sirv": "^3.0.1",
"site-config-stack": "3.1.9",
"ufo": "^1.5.4"
},
"funding": {
"url": "https://github.com/sponsors/harlan-zw"
}
},
"node_modules/nuxt-site-config-kit": {
"version": "3.1.9",
"resolved": "https://registry.npmjs.org/nuxt-site-config-kit/-/nuxt-site-config-kit-3.1.9.tgz",
"integrity": "sha512-bcmpajYJgkNzA0jTq6CmmhKF2wHZUUKeVx/CIGI8lwWuAD81EBUZN0T4iKvVDo54g9UBrUUl8/5GhD65YBBG0A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nuxt/kit": "^3.16.2",
"pkg-types": "^2.1.0",
"site-config-stack": "3.1.9",
"std-env": "^3.9.0",
"ufo": "^1.5.4"
},
"funding": {
"url": "https://github.com/sponsors/harlan-zw"
}
},
"node_modules/nuxt-site-config-kit/node_modules/@nuxt/kit": {
"version": "3.16.2",
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.16.2.tgz",
"integrity": "sha512-K1SAUo2vweTfudKZzjKsZ5YJoxPLTspR5qz5+G61xtZreLpsdpDYfBseqsIAl5VFLJuszeRpWQ01jP9LfQ6Ksw==",
"dev": true,
"license": "MIT",
"dependencies": {
"c12": "^3.0.2",
"consola": "^3.4.2",
"defu": "^6.1.4",
"destr": "^2.0.3",
"errx": "^0.1.0",
"exsolve": "^1.0.4",
"globby": "^14.1.0",
"ignore": "^7.0.3",
"jiti": "^2.4.2",
"klona": "^2.0.6",
"knitwork": "^1.2.0",
"mlly": "^1.7.4",
"ohash": "^2.0.11",
"pathe": "^2.0.3",
"pkg-types": "^2.1.0",
"scule": "^1.3.0",
"semver": "^7.7.1",
"std-env": "^3.8.1",
"ufo": "^1.5.4",
"unctx": "^2.4.1",
"unimport": "^4.1.3",
"untyped": "^2.0.0"
},
"engines": {
"node": ">=18.12.0"
}
},
"node_modules/nuxt-site-config/node_modules/@nuxt/kit": {
"version": "3.16.2",
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.16.2.tgz",
"integrity": "sha512-K1SAUo2vweTfudKZzjKsZ5YJoxPLTspR5qz5+G61xtZreLpsdpDYfBseqsIAl5VFLJuszeRpWQ01jP9LfQ6Ksw==",
"dev": true,
"license": "MIT",
"dependencies": {
"c12": "^3.0.2",
"consola": "^3.4.2",
"defu": "^6.1.4",
"destr": "^2.0.3",
"errx": "^0.1.0",
"exsolve": "^1.0.4",
"globby": "^14.1.0",
"ignore": "^7.0.3",
"jiti": "^2.4.2",
"klona": "^2.0.6",
"knitwork": "^1.2.0",
"mlly": "^1.7.4",
"ohash": "^2.0.11",
"pathe": "^2.0.3",
"pkg-types": "^2.1.0",
"scule": "^1.3.0",
"semver": "^7.7.1",
"std-env": "^3.8.1",
"ufo": "^1.5.4",
"unctx": "^2.4.1",
"unimport": "^4.1.3",
"untyped": "^2.0.0"
},
"engines": {
"node": ">=18.12.0"
}
},
"node_modules/nuxt/node_modules/estree-walker": {
"version": "3.0.3",
"dev": true,
@@ -10419,6 +10668,22 @@
"dev": true,
"license": "MIT"
},
"node_modules/site-config-stack": {
"version": "3.1.9",
"resolved": "https://registry.npmjs.org/site-config-stack/-/site-config-stack-3.1.9.tgz",
"integrity": "sha512-ed53+wLi+36SGqidU+YUpl7f1OHClPLmvUJ/aYZny1dCBnXvOsuFottrMkXDIK2N5UaMED9mz8KrRZTk94ARCg==",
"dev": true,
"license": "MIT",
"dependencies": {
"ufo": "^1.5.4"
},
"funding": {
"url": "https://github.com/sponsors/harlan-zw"
},
"peerDependencies": {
"vue": "^3"
}
},
"node_modules/skin-tone": {
"version": "2.0.0",
"dev": true,
@@ -10620,7 +10885,9 @@
}
},
"node_modules/std-env": {
"version": "3.8.1",
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz",
"integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
"license": "MIT"
},
"node_modules/streamx": {
+2
View File
@@ -25,6 +25,8 @@
"@iconify-json/fa-solid": "^1.2.1",
"@nuxt/content": "^3.4.0",
"@nuxt/eslint": "^1.2.0",
"@nuxtjs/robots": "^5.2.9",
"@nuxtjs/sitemap": "^7.2.10",
"@types/bootstrap": "^5.2.10",
"@vue/language-server": "^2.1.10",
"@vue/typescript-plugin": "^2.1.10",
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-1
View File
@@ -1 +0,0 @@
+4 -1
View File
@@ -16,8 +16,11 @@ const store = useStateStore();
store.applyColorMode();
useHead({
link: [
{ rel: "icon", type: "image/x-icon", href: getPublicPath("/favicon.ico") },
],
titleTemplate: (titleChunk: string | undefined): string | null => {
return titleChunk ? `${titleChunk} - website-vue` : 'website-vue';
return titleChunk ? `${titleChunk} - Rick van Vonderen` : 'Rick van Vonderen';
}
})
-8
View File
@@ -8,25 +8,17 @@ export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
IBi0Circle: typeof import('~icons/bi/0-circle')['default']
IBiActivity: typeof import('~icons/bi/activity')['default']
IFaAdjust: typeof import('~icons/fa/adjust')['default']
IFaAngellist: typeof import('~icons/fa/angellist')['default']
IFaCheck: typeof import('~icons/fa/check')['default']
IFaClone: typeof import('~icons/fa/clone')['default']
IFaCoffee: typeof import('~icons/fa/coffee')['default']
IFaCope: typeof import('~icons/fa/cope')['default']
IFaCopy: typeof import('~icons/fa/copy')['default']
IFaGithub: typeof import('~icons/fa/github')['default']
IFaGitlab: typeof import('~icons/fa/gitlab')['default']
IFaHome: typeof import('~icons/fa/home')['default']
IFaImage: typeof import('~icons/fa/image')['default']
IFaLink: typeof import('~icons/fa/link')['default']
IFaLinkedinSquare: typeof import('~icons/fa/linkedin-square')['default']
IFaMoonO: typeof import('~icons/fa/moon-o')['default']
IFaSolidMoon: typeof import('~icons/fa-solid/moon')['default']
IFaSolidSun: typeof import('~icons/fa-solid/sun')['default']
IMdiAccountBox: typeof import('~icons/mdi/account-box')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}
+3 -3
View File
@@ -2,10 +2,10 @@
<h2>CV</h2>
<p>
Download the PDF here:
<a href="https://riyyi.com/media/cv-en-rick-van-vonderen.pdf">English</a>,&nbsp;
<a href="https://riyyi.com/media/cv-rick-van-vonderen.pdf">Nederlands</a>
<a :href="getPublicPath('/pdf/cv-en-rick-van-vonderen.pdf')" target="_blank">English</a>,&nbsp;
<a :href="getPublicPath('/pdf/cv-rick-van-vonderen.pdf')" target="_blank">Nederlands</a>
</p>
<object data="https://riyyi.com/media/cv-en-rick-van-vonderen.pdf" type="application/pdf"
<object :data="getPublicPath('/pdf/cv-en-rick-van-vonderen.pdf')" type="application/pdf"
style="width: 100%; height: calc(100vh - 280px)"></object>
</template>
+1 -4
View File
@@ -69,8 +69,5 @@ const { data: article } = await useAsyncData<ContentCollectionItem | null>(
() => queryCollection("content").path("/articles/" + params.slug).first()
);
useSeoMeta({
title: article.value?.title,
description: article.value?.description
})
useSeoMeta(article.value?.seo || {});
</script>