mirror of
https://github.com/olehomelchenko/olehomelchenko.com.git
synced 2026-02-05 02:54:37 +00:00
feat: set up migration to quarto
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -9,3 +9,7 @@ hugo.darwin
|
||||
|
||||
.DS_Store
|
||||
.vscode/
|
||||
|
||||
# Quarto
|
||||
/.quarto/
|
||||
/_site/
|
||||
|
||||
66
MIGRATION-CHECKLIST.md
Normal file
66
MIGRATION-CHECKLIST.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Migration Checklist
|
||||
|
||||
## 📋 Content Migration
|
||||
|
||||
### Blog Posts (8 total)
|
||||
- [ ] `dataviz-blogs.md` → `posts/dataviz-blogs/index.qmd` (lang: uk)
|
||||
- [ ] `dataviz-books-ua.md` → `posts/dataviz-books-ua/index.qmd` (lang: uk)
|
||||
- [ ] `entso-e-ukraine-energy-transfer-viz.md` → `posts/entso-e-ukraine-energy-transfer-viz/index.qmd` (lang: uk, **showcase**)
|
||||
- [ ] `forbes-50-foundations.md` → `posts/forbes-50-foundations/index.qmd` (lang: uk, **showcase**)
|
||||
- [ ] `my-first-post.md` → `posts/my-first-post/index.qmd` (lang: uk)
|
||||
- [ ] `vega-altair-hugo-shortcodes.md` → `posts/vega-altair-hugo-shortcodes/index.qmd` (lang: uk, **showcase**)
|
||||
- [ ] `bar-charts-makeover.md` (English) → `posts/bar-charts-makeover/index.qmd` (lang: en, **showcase**)
|
||||
- [ ] Convert all Vega-Lite shortcodes to code fences
|
||||
|
||||
### TILs (2 total)
|
||||
- [ ] `inspired-by-blogs.md` → `til/inspired-by-blogs.qmd` (lang: uk)
|
||||
- [ ] `obsidian-paperless.md` → `til/obsidian-paperless.qmd` (lang: uk)
|
||||
|
||||
## 🎨 Customization
|
||||
|
||||
- [ ] Update `about/index.qmd` with your actual bio
|
||||
- [ ] Add contact information to About page
|
||||
- [ ] Add any real projects to `projects/` section
|
||||
- [ ] Customize homepage (`index.qmd`) if desired
|
||||
- [ ] Review and adjust theme colors in `styles.css` if needed
|
||||
|
||||
## 🧹 Cleanup
|
||||
|
||||
- [ ] Delete `posts/sample-ukrainian-post/`
|
||||
- [ ] Delete `posts/sample-english-post/`
|
||||
- [ ] Delete `posts/sample-visualization-post/`
|
||||
- [ ] Delete `til/sample-til-ukrainian.qmd`
|
||||
- [ ] Delete `til/sample-til-english.qmd`
|
||||
- [ ] Delete `projects/sample-project-1/`
|
||||
|
||||
## ✅ Testing
|
||||
|
||||
- [ ] Run `quarto preview` and check all pages
|
||||
- [ ] Verify all blog posts render correctly
|
||||
- [ ] Verify all TILs render correctly
|
||||
- [ ] Check all Vega-Lite visualizations display properly
|
||||
- [ ] Test portfolio page shows showcase items
|
||||
- [ ] Test navigation between all sections
|
||||
- [ ] Check responsive design on mobile
|
||||
- [ ] Verify analytics scripts load (check browser console)
|
||||
|
||||
## 🚀 Deployment
|
||||
|
||||
- [ ] Run `quarto render` successfully
|
||||
- [ ] Check build output in `_site/`
|
||||
- [ ] Test old `/en/*` URL redirects
|
||||
- [ ] Deploy `_site/` to hosting
|
||||
- [ ] Verify production site works correctly
|
||||
- [ ] Update DNS if needed
|
||||
|
||||
## 🗑️ Final Cleanup (After Successful Deployment)
|
||||
|
||||
- [ ] Archive or delete Hugo `content/` directory
|
||||
- [ ] Delete `archetypes/`, `layouts/`, `themes/`
|
||||
- [ ] Delete `hugo.yaml`
|
||||
- [ ] Delete `public/`, `resources/`
|
||||
- [ ] Keep `.git/` and version control as-is
|
||||
|
||||
---
|
||||
|
||||
**Tip:** Test with one post first to validate the workflow before batch-migrating everything!
|
||||
250
MIGRATION-README.md
Normal file
250
MIGRATION-README.md
Normal file
@@ -0,0 +1,250 @@
|
||||
# Hugo to Quarto Migration Guide
|
||||
|
||||
## ✅ Migration Status: Infrastructure Complete
|
||||
|
||||
The Quarto site infrastructure is now fully set up! The site builds successfully and is ready for content migration.
|
||||
|
||||
## 🏗️ What's Been Created
|
||||
|
||||
### Configuration
|
||||
- `_quarto.yml` - Main site configuration with navbar, footer, analytics, **Vega-Lite filter**
|
||||
- `vega-lite.lua` - **Lua filter for Vega-Lite support** (Quarto doesn't have native support)
|
||||
- `styles.css` - Minimal custom styling (Vega chart centering)
|
||||
- `_includes/analytics.html` - Plausible + Matomo analytics
|
||||
- `_redirects` - URL redirects for old `/en/*` paths
|
||||
- `.gitignore` - Updated with Quarto-specific entries
|
||||
|
||||
### Directory Structure
|
||||
```
|
||||
├── posts/ # Blog posts (3 sample placeholders)
|
||||
├── til/ # TILs (2 sample placeholders)
|
||||
├── portfolio/ # Portfolio listing page
|
||||
├── projects/ # Projects section (1 sample project)
|
||||
├── about/ # About page template
|
||||
└── index.qmd # Homepage
|
||||
```
|
||||
|
||||
### Sample Content (Placeholders)
|
||||
- `posts/sample-ukrainian-post/` - Example Ukrainian post structure
|
||||
- `posts/sample-english-post/` - Example English post structure
|
||||
- `posts/sample-visualization-post/` - Example with Vega-Lite chart
|
||||
- `til/sample-til-ukrainian.qmd` - Example Ukrainian TIL
|
||||
- `til/sample-til-english.qmd` - Example English TIL
|
||||
- `projects/sample-project-1/` - Example full project page
|
||||
|
||||
## 📝 Manual Migration Steps
|
||||
|
||||
### 1. Migrate Blog Posts (8 posts)
|
||||
|
||||
For each Hugo post in `content/posts/` and `content/en/posts/`:
|
||||
|
||||
1. **Create directory:** `posts/{post-slug}/`
|
||||
2. **Convert file:** Copy `.md` → `index.qmd` in the new directory
|
||||
3. **Update frontmatter:**
|
||||
```yaml
|
||||
---
|
||||
title: "Your Title"
|
||||
date: "YYYY-MM-DD"
|
||||
lang: uk # or 'en' for English posts
|
||||
categories:
|
||||
- dataviz
|
||||
- showcase # Add this for portfolio items!
|
||||
description: "Brief description"
|
||||
---
|
||||
```
|
||||
4. **Convert Vega-Lite shortcodes:**
|
||||
- Remove: `{{</* vega-lite id="..." */>}}...{{</* /vega-lite */>}}`
|
||||
- Replace with:
|
||||
````markdown
|
||||
```{vega-lite}
|
||||
{your vega spec here}
|
||||
```
|
||||
````
|
||||
- See `VEGA-LITE-SETUP.md` for detailed instructions
|
||||
|
||||
**Posts to migrate:**
|
||||
- `content/posts/dataviz-blogs.md` → `posts/dataviz-blogs/index.qmd`
|
||||
- `content/posts/dataviz-books-ua.md` → `posts/dataviz-books-ua/index.qmd`
|
||||
- `content/posts/entso-e-ukraine-energy-transfer-viz.md` → `posts/entso-e-ukraine-energy-transfer-viz/index.qmd`
|
||||
- `content/posts/forbes-50-foundations.md` → `posts/forbes-50-foundations/index.qmd` **(add 'showcase' category)**
|
||||
- `content/posts/my-first-post.md` → `posts/my-first-post/index.qmd`
|
||||
- `content/posts/vega-altair-hugo-shortcodes.md` → `posts/vega-altair-hugo-shortcodes/index.qmd` **(add 'showcase' category)**
|
||||
- `content/en/posts/bar-charts-makeover.md` → `posts/bar-charts-makeover/index.qmd` **(add 'showcase' category, lang: en)**
|
||||
|
||||
### 2. Migrate TILs (2 posts)
|
||||
|
||||
For each Hugo TIL in `content/til/`:
|
||||
|
||||
1. **Convert file:** Copy `.md` → `.qmd` directly in `til/` folder
|
||||
2. **Update frontmatter:**
|
||||
```yaml
|
||||
---
|
||||
title: "Your Title"
|
||||
date: "YYYY-MM-DD"
|
||||
lang: uk
|
||||
categories:
|
||||
- tools
|
||||
---
|
||||
```
|
||||
|
||||
**TILs to migrate:**
|
||||
- `content/til/inspired-by-blogs.md` → `til/inspired-by-blogs.qmd`
|
||||
- `content/til/obsidian-paperless.md` → `til/obsidian-paperless.qmd`
|
||||
|
||||
### 3. Posts/TILs Auto-Discovery
|
||||
|
||||
✅ **Good news!** The listing pages automatically discover new posts and TILs:
|
||||
|
||||
- **Posts:** Any directory with `index.qmd` in `posts/` appears automatically
|
||||
- **TILs:** Any `.qmd` file in `til/` appears automatically
|
||||
- **No manual updates needed!** Just add your files and they'll show up
|
||||
|
||||
### 4. Update Portfolio Page
|
||||
|
||||
The portfolio page needs manual updates. Edit `portfolio/index.qmd` and add your showcase posts:
|
||||
|
||||
```markdown
|
||||
::: {.g-col-12 .g-col-md-6}
|
||||
### [Forbes Top-50 Foundations](../posts/forbes-50-foundations/)
|
||||
Interactive visualization of Ukraine's top charitable foundations
|
||||
:::
|
||||
|
||||
::: {.g-col-12 .g-col-md-6}
|
||||
### [Bar Charts Makeover](../posts/bar-charts-makeover/)
|
||||
Seven ways to visualize year-over-year growth
|
||||
:::
|
||||
```
|
||||
|
||||
### 5. Delete Sample Placeholders
|
||||
|
||||
After migrating and updating listings, delete these placeholder files:
|
||||
```bash
|
||||
rm -rf posts/sample-*
|
||||
rm til/sample-*
|
||||
rm -rf projects/sample-project-1
|
||||
```
|
||||
|
||||
### 6. Customize About Page
|
||||
|
||||
Edit `about/index.qmd` and replace template content with:
|
||||
- Your bio
|
||||
- Skills and expertise
|
||||
- Contact information
|
||||
- Links to social profiles
|
||||
|
||||
### 7. Add Real Projects
|
||||
|
||||
Option A: Full project page
|
||||
```bash
|
||||
mkdir projects/your-project-name
|
||||
# Create projects/your-project-name/index.qmd
|
||||
```
|
||||
|
||||
Option B: Just list in `projects/index.qmd`
|
||||
|
||||
## 🔧 Key Technical Details
|
||||
|
||||
### Language Tags
|
||||
Use `lang: uk` or `lang: en` in frontmatter to tag content language. This allows filtering by language if needed.
|
||||
|
||||
### Portfolio Items
|
||||
Add `showcase` to the categories list for any post you want in your portfolio:
|
||||
```yaml
|
||||
categories:
|
||||
- dataviz
|
||||
- showcase # This makes it appear in portfolio
|
||||
```
|
||||
|
||||
### Vega-Lite Visualizations
|
||||
Enabled via `vega-lite.lua` filter (already configured). Use:
|
||||
````markdown
|
||||
```{vega-lite}
|
||||
{
|
||||
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
|
||||
"mark": "bar",
|
||||
...
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
Optional attributes:
|
||||
- `#| echo: false` - Hide code, show only visualization
|
||||
- `#| code-fold: true` - Make code collapsible
|
||||
|
||||
See `VEGA-LITE-SETUP.md` for complete documentation.
|
||||
|
||||
## 🚀 Building & Previewing
|
||||
|
||||
### Local Preview
|
||||
```bash
|
||||
quarto preview
|
||||
```
|
||||
Opens at `http://localhost:4848`
|
||||
|
||||
### Build Site
|
||||
```bash
|
||||
quarto render
|
||||
```
|
||||
Output goes to `_site/`
|
||||
|
||||
### Check for Errors
|
||||
```bash
|
||||
quarto check
|
||||
```
|
||||
|
||||
## 📂 What to Keep vs Delete
|
||||
|
||||
### Keep (Quarto):
|
||||
- All `*.qmd` files
|
||||
- `_quarto.yml`
|
||||
- `styles.css`
|
||||
- `_includes/`
|
||||
- `_redirects`
|
||||
- `_site/` (build output)
|
||||
|
||||
### Can Eventually Delete (Hugo):
|
||||
- `archetypes/`
|
||||
- `content/` (after migrating to `posts/` and `til/`)
|
||||
- `data/`
|
||||
- `i18n/`
|
||||
- `layouts/`
|
||||
- `public/`
|
||||
- `resources/`
|
||||
- `static/`
|
||||
- `templates/`
|
||||
- `themes/`
|
||||
- `hugo.yaml`
|
||||
|
||||
**Don't delete Hugo files yet!** Wait until you've confirmed the Quarto migration is complete and deployed.
|
||||
|
||||
## 🌐 Deployment
|
||||
|
||||
1. Build: `quarto render`
|
||||
2. Deploy `_site/` directory to your hosting
|
||||
3. Ensure `_redirects` file is included for old URL support
|
||||
|
||||
## 📌 Important Notes
|
||||
|
||||
- **URL Preservation:** Old `/en/posts/*` URLs will redirect to `/posts/*` via `_redirects`
|
||||
- **Analytics:** Already integrated (Plausible + Matomo)
|
||||
- **No Language Duplication:** All posts in one location, tagged with `lang` field
|
||||
- **Sample Content:** Delete all `sample-*` files after migrating real content
|
||||
|
||||
## ✨ Benefits You'll Gain
|
||||
|
||||
1. ✅ Vega-Lite support via Lua filter (cleaner than Hugo shortcodes)
|
||||
2. ✅ Can add Python/R code that generates visualizations
|
||||
3. ✅ Observable JS for interactive dashboards
|
||||
4. ✅ Better data analysis workflows
|
||||
5. ✅ Single source of truth (no language directory duplication)
|
||||
6. ✅ Cleaner, more maintainable structure
|
||||
|
||||
## 📚 Additional Documentation
|
||||
|
||||
- **`VEGA-LITE-SETUP.md`** - Complete guide to Vega-Lite filter and usage
|
||||
- **`QUICK-START.md`** - How to use Quarto, add posts, common commands
|
||||
- **`MIGRATION-CHECKLIST.md`** - Checkbox list to track migration progress
|
||||
|
||||
---
|
||||
|
||||
**Ready to migrate!** Start with one post to test the workflow, then batch-migrate the rest.
|
||||
132
QUICK-START.md
Normal file
132
QUICK-START.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Quick Start Guide
|
||||
|
||||
## ✅ Setup is Complete!
|
||||
|
||||
The Quarto site infrastructure is ready. Here's how to work with it:
|
||||
|
||||
## 🚀 Preview the Site
|
||||
|
||||
```bash
|
||||
quarto preview
|
||||
```
|
||||
Opens at http://localhost:4848 with live reload.
|
||||
|
||||
## 🎨 Theme & Styling
|
||||
|
||||
- **Theme:** Cosmo (clean, minimal Bootstrap theme)
|
||||
- **Custom CSS:** `styles.css` (minimal - just Vega chart centering)
|
||||
- To change theme, edit `_quarto.yml` and try: cosmo, flatly, litera, minty, etc.
|
||||
|
||||
## 📝 Adding Your First Real Post
|
||||
|
||||
1. **Create post directory:**
|
||||
```bash
|
||||
mkdir posts/your-post-slug
|
||||
```
|
||||
|
||||
2. **Create `posts/your-post-slug/index.qmd`:**
|
||||
```yaml
|
||||
---
|
||||
title: "Your Post Title"
|
||||
date: "2024-03-15"
|
||||
lang: uk # or 'en'
|
||||
categories:
|
||||
- dataviz
|
||||
- showcase # Include for portfolio items
|
||||
description: "Brief description"
|
||||
---
|
||||
|
||||
Your content here...
|
||||
```
|
||||
|
||||
3. **Preview changes** (posts auto-discovered!):
|
||||
```bash
|
||||
quarto preview
|
||||
```
|
||||
|
||||
✅ Your new post will automatically appear in the listing - no manual updates needed!
|
||||
|
||||
## 📊 Using Vega-Lite Visualizations
|
||||
|
||||
**Important:** This project uses `vega-lite.lua` filter for Vega-Lite support.
|
||||
|
||||
**Hugo shortcode (OLD):**
|
||||
```markdown
|
||||
{{</* vega-lite id="chart1" */>}}
|
||||
{vega spec}
|
||||
{{</* /vega-lite */>}}
|
||||
```
|
||||
|
||||
**Quarto with Lua filter (NEW):**
|
||||
````markdown
|
||||
```{vega-lite}
|
||||
{vega spec}
|
||||
```
|
||||
````
|
||||
|
||||
**With options:**
|
||||
````markdown
|
||||
```{vega-lite}
|
||||
#| echo: false
|
||||
#| code-fold: true
|
||||
{vega spec}
|
||||
```
|
||||
````
|
||||
|
||||
See **`VEGA-LITE-SETUP.md`** for complete documentation and examples.
|
||||
|
||||
## 🔧 Common Commands
|
||||
|
||||
```bash
|
||||
# Preview with live reload
|
||||
quarto preview
|
||||
|
||||
# Build the site
|
||||
quarto render
|
||||
|
||||
# Check for issues
|
||||
quarto check
|
||||
|
||||
# Clean build cache
|
||||
quarto clean
|
||||
```
|
||||
|
||||
## 📂 Where Things Go
|
||||
|
||||
- **Blog posts:** `posts/post-slug/index.qmd`
|
||||
- **TILs:** `til/post-name.qmd`
|
||||
- **Projects:** `projects/project-name/index.qmd` (or just list in `projects/index.qmd`)
|
||||
- **About page:** `about/index.qmd`
|
||||
- **Homepage:** `index.qmd`
|
||||
|
||||
## ⚠️ Important Notes
|
||||
|
||||
1. **Use `lang: uk` or `lang: en`** (not `language:` - that's reserved by Quarto)
|
||||
2. **Update listing pages** when you add real content (see MIGRATION-README.md)
|
||||
3. **Posts with `showcase` category** automatically appear in portfolio
|
||||
4. **Delete sample files** after migrating your real content
|
||||
|
||||
## 🆘 Troubleshooting
|
||||
|
||||
**Error: "list needs to have at least one item"**
|
||||
- Update the listing `contents:` in the index page to reference actual files/directories
|
||||
|
||||
**Vega chart not showing:**
|
||||
- Check the JSON is valid
|
||||
- Ensure you're using ````{vega-lite}` code fence (not `{json}`)
|
||||
- Check browser console for errors
|
||||
|
||||
**Styles look wrong:**
|
||||
- Run `quarto clean && quarto render` to rebuild from scratch
|
||||
- Check `styles.css` hasn't been corrupted
|
||||
|
||||
## 📚 Next Steps
|
||||
|
||||
1. Test by migrating one post from Hugo
|
||||
2. Verify it displays correctly
|
||||
3. Batch migrate the rest
|
||||
4. Update all listing pages
|
||||
5. Delete sample placeholders
|
||||
6. Deploy!
|
||||
|
||||
See `MIGRATION-README.md` for detailed migration instructions.
|
||||
181
VEGA-LITE-SETUP.md
Normal file
181
VEGA-LITE-SETUP.md
Normal file
@@ -0,0 +1,181 @@
|
||||
# Vega-Lite Setup with Quarto
|
||||
|
||||
## Important: Vega-Lite Lua Filter Required
|
||||
|
||||
**Quarto does NOT have native Vega-Lite support out of the box.** This project uses `vega-lite.lua` - a Quarto filter that enables Vega-Lite visualization rendering.
|
||||
|
||||
## ✅ What's Already Configured
|
||||
|
||||
1. **`vega-lite.lua`** - Custom Lua filter that processes Vega-Lite code blocks
|
||||
2. **`_quarto.yml`** - Already configured to use the filter:
|
||||
```yaml
|
||||
filters:
|
||||
- vega-lite.lua
|
||||
```
|
||||
|
||||
## 🎨 How to Use Vega-Lite in Your Posts
|
||||
|
||||
### Basic Usage
|
||||
|
||||
````markdown
|
||||
```{vega-lite}
|
||||
{
|
||||
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
|
||||
"data": {
|
||||
"values": [
|
||||
{"category": "A", "value": 28},
|
||||
{"category": "B", "value": 55}
|
||||
]
|
||||
},
|
||||
"mark": "bar",
|
||||
"encoding": {
|
||||
"x": {"field": "category", "type": "nominal"},
|
||||
"y": {"field": "value", "type": "quantitative"}
|
||||
}
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
### With Options
|
||||
|
||||
````markdown
|
||||
```{vega-lite}
|
||||
#| echo: false
|
||||
#| code-fold: true
|
||||
{your vega spec}
|
||||
```
|
||||
````
|
||||
|
||||
**Supported options:**
|
||||
- `echo: false` - Hide the code, show only the visualization
|
||||
- `echo: true` - Show both code and visualization (default)
|
||||
- `code-fold: true` - Make code collapsible (collapsed by default)
|
||||
- `code-fold: show` - Make code collapsible but open by default
|
||||
|
||||
## 🔧 How the Filter Works
|
||||
|
||||
The `vega-lite.lua` filter:
|
||||
|
||||
1. **Detects** code blocks with class `vega-lite`
|
||||
2. **Includes** Vega libraries (Vega, Vega-Lite, Vega-Embed) from CDN
|
||||
3. **Renders** the specification using `vegaEmbed()` JavaScript
|
||||
4. **Handles** code display options (echo, code-fold)
|
||||
|
||||
### Libraries Loaded
|
||||
- `vega@5` - Core Vega library
|
||||
- `vega-lite@5` - Vega-Lite library
|
||||
- `vega-embed@6` - Embedding library
|
||||
|
||||
## 📝 Migrating from Hugo Shortcodes
|
||||
|
||||
**Hugo shortcode (OLD):**
|
||||
```markdown
|
||||
{{</* vega-lite id="chart-bar-in-bar" actions="true" */>}}
|
||||
{
|
||||
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
|
||||
"mark": "bar",
|
||||
...
|
||||
}
|
||||
{{</* /vega-lite */>}}
|
||||
```
|
||||
|
||||
**Quarto with Lua filter (NEW):**
|
||||
````markdown
|
||||
```{vega-lite}
|
||||
{
|
||||
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
|
||||
"mark": "bar",
|
||||
...
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
**Key differences:**
|
||||
- No need for `id` attribute - filter auto-generates unique IDs
|
||||
- No `actions` attribute - actions toolbar enabled by default
|
||||
- No `load_vega` frontmatter needed - filter includes libraries automatically
|
||||
- Just paste your Vega-Lite JSON spec inside the code fence!
|
||||
|
||||
## 🎯 Migration Steps for Vega Posts
|
||||
|
||||
1. **Find Hugo shortcode:**
|
||||
```markdown
|
||||
{{</* vega-lite id="..." */>}}
|
||||
```
|
||||
|
||||
2. **Copy the JSON spec** (everything between the shortcode tags)
|
||||
|
||||
3. **Replace with code fence:**
|
||||
````markdown
|
||||
```{vega-lite}
|
||||
{your JSON spec here}
|
||||
```
|
||||
````
|
||||
|
||||
4. **Remove** the `load_vega: true` from frontmatter (no longer needed)
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
After adding a Vega-Lite visualization:
|
||||
|
||||
1. **Build:** `quarto render`
|
||||
2. **Preview:** `quarto preview`
|
||||
3. **Check:**
|
||||
- Visualization renders correctly
|
||||
- Actions toolbar appears (export PNG/SVG/etc.)
|
||||
- No errors in browser console
|
||||
- Code display respects your echo/fold settings
|
||||
|
||||
## 📋 Example Post with Visualization
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: "My Vega-Lite Post"
|
||||
date: "2024-03-15"
|
||||
lang: en
|
||||
categories:
|
||||
- dataviz
|
||||
- showcase
|
||||
---
|
||||
|
||||
## Simple Bar Chart
|
||||
|
||||
```{vega-lite}
|
||||
{
|
||||
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
|
||||
"description": "A simple bar chart",
|
||||
"data": {
|
||||
"values": [
|
||||
{"category": "A", "value": 28},
|
||||
{"category": "B", "value": 55},
|
||||
{"category": "C", "value": 43}
|
||||
]
|
||||
},
|
||||
"mark": "bar",
|
||||
"encoding": {
|
||||
"x": {"field": "category", "type": "nominal"},
|
||||
"y": {"field": "value", "type": "quantitative"}
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
## 🔗 Additional Resources
|
||||
|
||||
- [Vega-Lite Documentation](https://vega.github.io/vega-lite/)
|
||||
- [Vega-Lite Examples](https://vega.github.io/vega-lite/examples/)
|
||||
- [Quarto Filters Guide](https://quarto.org/docs/extensions/filters.html)
|
||||
|
||||
## ⚠️ Troubleshooting
|
||||
|
||||
**Visualization not rendering:**
|
||||
- Check that `vega-lite.lua` exists in the project root
|
||||
- Verify `filters: - vega-lite.lua` is in `_quarto.yml`
|
||||
- Ensure JSON spec is valid (test at https://vega.github.io/editor/)
|
||||
|
||||
**Browser console errors:**
|
||||
- Check network tab for CDN library loading issues
|
||||
- Verify Vega-Lite spec schema version matches (v5)
|
||||
|
||||
**Code block shown as plain text:**
|
||||
- Make sure you're using ````{vega-lite}` not ````{json}` or ````json`
|
||||
17
_includes/analytics.html
Normal file
17
_includes/analytics.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!-- Plausible Analytics -->
|
||||
<script defer data-domain="olehomelchenko.com" src="https://plausible.io/js/script.file-downloads.outbound-links.tagged-events.js"></script>
|
||||
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
|
||||
|
||||
<!-- Matomo Analytics -->
|
||||
<script>
|
||||
var _paq = window._paq = window._paq || [];
|
||||
_paq.push(['trackPageView']);
|
||||
_paq.push(['enableLinkTracking']);
|
||||
(function () {
|
||||
var u = "//matomo.olehomelchenko.com/";
|
||||
_paq.push(['setTrackerUrl', u + 'matomo.php']);
|
||||
_paq.push(['setSiteId', '1']);
|
||||
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
|
||||
g.async = true; g.src = u + 'matomo.js'; s.parentNode.insertBefore(g, s);
|
||||
})();
|
||||
</script>
|
||||
59
_quarto.yml
Normal file
59
_quarto.yml
Normal file
@@ -0,0 +1,59 @@
|
||||
project:
|
||||
type: website
|
||||
output-dir: _site
|
||||
render:
|
||||
- "*.qmd"
|
||||
- "!archetypes/"
|
||||
- "!content/"
|
||||
- "!data/"
|
||||
- "!i18n/"
|
||||
- "!layouts/"
|
||||
- "!public/"
|
||||
- "!resources/"
|
||||
- "!static/"
|
||||
- "!templates/"
|
||||
- "!themes/"
|
||||
|
||||
filters:
|
||||
- vega-lite.lua
|
||||
|
||||
website:
|
||||
title: "Oleh Omelchenko"
|
||||
site-url: "https://olehomelchenko.com"
|
||||
description: "Data visualization and analysis blog"
|
||||
|
||||
navbar:
|
||||
background: light
|
||||
left:
|
||||
- text: "Posts"
|
||||
href: posts/index.qmd
|
||||
- text: "TILs"
|
||||
href: til/index.qmd
|
||||
- text: "Portfolio"
|
||||
href: portfolio/index.qmd
|
||||
- text: "Projects"
|
||||
href: projects/index.qmd
|
||||
- text: "About"
|
||||
href: about/index.qmd
|
||||
right:
|
||||
- icon: github
|
||||
href: https://github.com/olehomelchenko
|
||||
aria-label: GitHub
|
||||
|
||||
page-footer:
|
||||
left: "© 2025 Oleh Omelchenko"
|
||||
right:
|
||||
- icon: github
|
||||
href: https://github.com/olehomelchenko
|
||||
aria-label: GitHub
|
||||
|
||||
format:
|
||||
html:
|
||||
theme: cosmo
|
||||
css: styles.css
|
||||
toc: false
|
||||
page-layout: article
|
||||
include-in-header: _includes/analytics.html
|
||||
|
||||
execute:
|
||||
freeze: auto
|
||||
6
_redirects
Normal file
6
_redirects
Normal file
@@ -0,0 +1,6 @@
|
||||
# Redirects for old Hugo URLs (English language paths)
|
||||
# Redirects old /en/* paths to the new unified structure
|
||||
|
||||
/en/posts/* /posts/:splat 301
|
||||
/en/til/* /til/:splat 301
|
||||
/en/* /:splat 301
|
||||
53
about/index.qmd
Normal file
53
about/index.qmd
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
title: "About"
|
||||
page-layout: article
|
||||
---
|
||||
|
||||
## Hi, I'm Oleh Omelchenko
|
||||
|
||||
<!-- Replace this template with your actual bio and information -->
|
||||
|
||||
### Background
|
||||
|
||||
Add your background, education, and experience here.
|
||||
|
||||
### Skills & Expertise
|
||||
|
||||
::: {.grid}
|
||||
|
||||
::: {.g-col-12 .g-col-md-4}
|
||||
**Data Visualization**
|
||||
- Vega-Lite
|
||||
- Python (Altair, Matplotlib)
|
||||
- R (ggplot2)
|
||||
:::
|
||||
|
||||
::: {.g-col-12 .g-col-md-4}
|
||||
**Analysis & Tools**
|
||||
- Python (pandas, numpy)
|
||||
- R
|
||||
- SQL
|
||||
:::
|
||||
|
||||
::: {.g-col-12 .g-col-md-4}
|
||||
**Communication**
|
||||
- Quarto
|
||||
- Jupyter Notebooks
|
||||
- Technical Writing
|
||||
:::
|
||||
|
||||
:::
|
||||
|
||||
### Projects
|
||||
|
||||
Check out my [portfolio](/portfolio/) and [projects](/projects/) pages to see examples of my work.
|
||||
|
||||
### Contact
|
||||
|
||||
- GitHub: [github.com/olehomelchenko](https://github.com/olehomelchenko)
|
||||
- Email: [your-email@example.com](mailto:your-email@example.com)
|
||||
- LinkedIn: [Add your LinkedIn URL]
|
||||
|
||||
---
|
||||
|
||||
*Replace this template with your actual information, accomplishments, and links.*
|
||||
41
index.qmd
Normal file
41
index.qmd
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
title: "Oleh Omelchenko"
|
||||
page-layout: full
|
||||
---
|
||||
|
||||
## Welcome
|
||||
|
||||
|
||||
Привіт! Я Олег, ви можете знати мене як аналітика в MacPaw та/або викладача в Київській школі економіки.
|
||||
|
||||
Цей сайт - сховище моїх знахідок в інтернеті, а також подекуди статей за темою аналізу та візуалізації даних.
|
||||
|
||||
|
||||

|
||||
|
||||
Data visualization enthusiast and analyst. This site showcases my work in data analysis, visualization, and storytelling with data.
|
||||
|
||||
### Recent Posts
|
||||
|
||||
::: {.grid}
|
||||
|
||||
::: {.g-col-12 .g-col-md-4}
|
||||
### [Posts](/posts/)
|
||||
Latest articles and analysis
|
||||
:::
|
||||
|
||||
::: {.g-col-12 .g-col-md-4}
|
||||
### [Portfolio](/portfolio/)
|
||||
Selected visualization work
|
||||
:::
|
||||
|
||||
::: {.g-col-12 .g-col-md-4}
|
||||
### [TILs](/til/)
|
||||
Quick tips and learnings
|
||||
:::
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
Explore my [projects](/projects/) or learn more [about me](/about/).
|
||||
26
portfolio/index.qmd
Normal file
26
portfolio/index.qmd
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: "Portfolio"
|
||||
page-layout: full
|
||||
---
|
||||
|
||||
Selected data visualization projects showcasing interactive charts, dashboards, and analytical narratives.
|
||||
|
||||
::: {.grid}
|
||||
|
||||
::: {.g-col-12 .g-col-md-6}
|
||||
### [Sample Visualization Post](../posts/sample-visualization-post/)
|
||||
Example post with Vega-Lite visualization - posts with the `showcase` category will appear here.
|
||||
:::
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
**Note:** After migrating your Hugo posts, manually add links here to your visualization-heavy posts (those with the `showcase` category). Example:
|
||||
|
||||
```markdown
|
||||
::: {.g-col-12 .g-col-md-6}
|
||||
### [Forbes Top-50 Foundations](../posts/forbes-50-foundations/)
|
||||
Interactive visualization of Ukraine's top charitable foundations
|
||||
:::
|
||||
```
|
||||
2
posts/_metadata.yml
Normal file
2
posts/_metadata.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
# Shared metadata for all posts
|
||||
freeze: auto
|
||||
16
posts/index.qmd
Normal file
16
posts/index.qmd
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
title: "Posts"
|
||||
page-layout: full
|
||||
listing:
|
||||
contents: "*.qmd"
|
||||
type: default
|
||||
sort: "date desc"
|
||||
categories: true
|
||||
sort-ui: true
|
||||
filter-ui: true
|
||||
fields: [date, title, reading-time, categories]
|
||||
date-format: "D MMMM YYYY"
|
||||
page-size: 10
|
||||
---
|
||||
|
||||
All blog posts covering data visualization, analysis, and related topics. Posts are available in both Ukrainian and English.
|
||||
25
posts/sample-english-post/index.qmd
Normal file
25
posts/sample-english-post/index.qmd
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
title: "Sample English Post"
|
||||
date: "2024-02-20"
|
||||
lang: en
|
||||
categories:
|
||||
- dataviz
|
||||
- tutorial
|
||||
description: "Example structure for an English post"
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
This is a sample English post. Replace this with your actual content from Hugo.
|
||||
|
||||
### Main Content
|
||||
|
||||
When you migrate your posts from Hugo, they will have this structure:
|
||||
|
||||
- Frontmatter with metadata (title, date, language, categories)
|
||||
- Markdown content
|
||||
- Support for Vega-Lite visualizations
|
||||
|
||||
## Conclusion
|
||||
|
||||
Replace this file with your actual Hugo posts.
|
||||
25
posts/sample-ukrainian-post/index.qmd
Normal file
25
posts/sample-ukrainian-post/index.qmd
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
title: "Зразок Української Статті"
|
||||
date: "2024-01-15"
|
||||
lang: uk
|
||||
categories:
|
||||
- dataviz
|
||||
- example
|
||||
description: "Приклад структури для української статті"
|
||||
---
|
||||
|
||||
## Вступ
|
||||
|
||||
Це зразок статті українською мовою. Тут ви можете додати свій контент.
|
||||
|
||||
### Основний зміст
|
||||
|
||||
Коли ви перенесете свої статті з Hugo, вони матимуть таку структуру:
|
||||
|
||||
- Frontmatter з метаданими (title, date, language, categories)
|
||||
- Markdown контент
|
||||
- Підтримка Vega-Lite візуалізацій
|
||||
|
||||
## Висновки
|
||||
|
||||
Замініть цей файл своїми реальними статтями з Hugo.
|
||||
55
posts/sample-visualization-post/index.qmd
Normal file
55
posts/sample-visualization-post/index.qmd
Normal file
@@ -0,0 +1,55 @@
|
||||
---
|
||||
title: "Sample Visualization Post"
|
||||
date: "2024-03-10"
|
||||
lang: en
|
||||
categories:
|
||||
- dataviz
|
||||
- showcase
|
||||
- vega-lite
|
||||
description: "Example post with Vega-Lite visualization"
|
||||
---
|
||||
|
||||
## Vega-Lite Example
|
||||
|
||||
This post demonstrates how to include Vega-Lite visualizations in Quarto. Note the `showcase` category - posts with this category will appear in your Portfolio.
|
||||
|
||||
### Simple Bar Chart
|
||||
|
||||
```{vega-lite}
|
||||
//| label: fig-simple-bar
|
||||
//| fig-cap: "A simple bar chart"
|
||||
{
|
||||
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
|
||||
"description": "A simple bar chart with embedded data.",
|
||||
"data": {
|
||||
"values": [
|
||||
{"category": "A", "value": 28},
|
||||
{"category": "B", "value": 55},
|
||||
{"category": "C", "value": 43},
|
||||
{"category": "D", "value": 91},
|
||||
{"category": "E", "value": 81}
|
||||
]
|
||||
},
|
||||
"mark": "bar",
|
||||
"encoding": {
|
||||
"x": {"field": "category", "type": "nominal", "axis": {"labelAngle": 0}},
|
||||
"y": {"field": "value", "type": "quantitative"}
|
||||
},
|
||||
"width": 400,
|
||||
"height": 300
|
||||
}
|
||||
```
|
||||
|
||||
### Migration Notes
|
||||
|
||||
When migrating from Hugo:
|
||||
|
||||
1. **Remove the Hugo shortcode**:
|
||||
- Old: `{{</* vega-lite id="chart1" */>}}...{{</* /vega-lite */>}}`
|
||||
|
||||
2. **Use Quarto code fence**:
|
||||
- New: ````{vega-lite}` with `//| label: chart-name`
|
||||
|
||||
3. **The visualization JSON stays the same** - just change the wrapper!
|
||||
|
||||
Replace this with your actual visualization posts from Hugo.
|
||||
30
projects/index.qmd
Normal file
30
projects/index.qmd
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
title: "Projects"
|
||||
page-layout: full
|
||||
---
|
||||
|
||||
## Featured Projects
|
||||
|
||||
::: {.grid}
|
||||
|
||||
::: {.g-col-12 .g-col-md-6}
|
||||
### [Sample Project 1](sample-project-1/)
|
||||
A full project page with detailed analysis and visualizations. Replace with your actual projects.
|
||||
:::
|
||||
|
||||
::: {.g-col-12 .g-col-md-6}
|
||||
### Sample Project 2
|
||||
A brief description without a dedicated page. Just a reference in the listing.
|
||||
:::
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Other Projects
|
||||
|
||||
- **Quick Project Reference 1** - Brief description
|
||||
- **Quick Project Reference 2** - Brief description
|
||||
- **Quick Project Reference 3** - Brief description
|
||||
|
||||
Some projects get full dedicated pages (like Sample Project 1 above), while others are just listed here with brief descriptions.
|
||||
32
projects/sample-project-1/index.qmd
Normal file
32
projects/sample-project-1/index.qmd
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
title: "Sample Project 1"
|
||||
subtitle: "Full Project Page Example"
|
||||
date: "2024-03-01"
|
||||
categories:
|
||||
- project
|
||||
- dataviz
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
This is an example of a full project page. Some projects warrant detailed explanations with multiple sections, code examples, and visualizations.
|
||||
|
||||
### Background
|
||||
|
||||
Describe the context and motivation for this project.
|
||||
|
||||
### Approach
|
||||
|
||||
Explain your methodology and approach.
|
||||
|
||||
### Results
|
||||
|
||||
Show your findings, visualizations, and analysis.
|
||||
|
||||
### Conclusions
|
||||
|
||||
Summarize the key takeaways.
|
||||
|
||||
---
|
||||
|
||||
Replace this with your actual project content.
|
||||
12
styles.css
Normal file
12
styles.css
Normal file
@@ -0,0 +1,12 @@
|
||||
/* Minimal custom styling for olehomelchenko.com */
|
||||
|
||||
/* Vega-Lite visualization styling - center and add subtle shadow */
|
||||
.vega-embed {
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.vega-embed canvas.marks {
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
margin: 10px;
|
||||
}
|
||||
2
til/_metadata.yml
Normal file
2
til/_metadata.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
# Shared metadata for TILs (Today I Learned)
|
||||
freeze: auto
|
||||
14
til/index.qmd
Normal file
14
til/index.qmd
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: "TILs - Today I Learned"
|
||||
page-layout: full
|
||||
listing:
|
||||
contents: "*.qmd"
|
||||
type: table
|
||||
sort: "date desc"
|
||||
fields: [date, title, categories]
|
||||
date-format: "YYYY-MM-DD"
|
||||
table-striped: true
|
||||
filter-ui: true
|
||||
---
|
||||
|
||||
Quick tips, discoveries, and learnings. Short-form content about interesting things I've discovered.
|
||||
14
til/sample-til-english.qmd
Normal file
14
til/sample-til-english.qmd
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: "Sample TIL (Today I Learned)"
|
||||
date: "2024-03-20"
|
||||
lang: en
|
||||
categories:
|
||||
- tools
|
||||
- quick-tip
|
||||
---
|
||||
|
||||
A short note about something interesting I learned today.
|
||||
|
||||
TIL articles are typically shorter than full blog posts and contain quick tips or useful discoveries.
|
||||
|
||||
Replace this file with your actual TILs from Hugo.
|
||||
14
til/sample-til-ukrainian.qmd
Normal file
14
til/sample-til-ukrainian.qmd
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: "Зразок TIL (Today I Learned)"
|
||||
date: "2024-03-15"
|
||||
lang: uk
|
||||
categories:
|
||||
- tools
|
||||
- quick-tip
|
||||
---
|
||||
|
||||
Короткий запис про щось цікаве, що я дізнався сьогодні.
|
||||
|
||||
TIL статті зазвичай коротші за повноцінні пости і містять швидкі поради або корисні знахідки.
|
||||
|
||||
Замініть цей файл своїми реальними TIL з Hugo.
|
||||
75
vega-lite.lua
Normal file
75
vega-lite.lua
Normal file
@@ -0,0 +1,75 @@
|
||||
-- vega-lite.lua
|
||||
-- A Quarto filter to render vega-lite code blocks using vega-embed
|
||||
|
||||
local vegaEmbedIncluded = false
|
||||
|
||||
function ensureVegaEmbed()
|
||||
if not vegaEmbedIncluded then
|
||||
vegaEmbedIncluded = true
|
||||
quarto.doc.include_text("in-header", [[
|
||||
<script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vega-lite@5"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>
|
||||
]])
|
||||
end
|
||||
end
|
||||
|
||||
local counter = 0
|
||||
|
||||
function CodeBlock(block)
|
||||
if block.classes:includes('vega-lite') then
|
||||
ensureVegaEmbed()
|
||||
|
||||
counter = counter + 1
|
||||
local divId = 'vega-viz-' .. counter
|
||||
|
||||
-- Get the spec as a string
|
||||
local spec = block.text
|
||||
|
||||
-- Parse options from attributes
|
||||
local echo = block.attributes['echo']
|
||||
local codeFold = block.attributes['code-fold']
|
||||
|
||||
-- Default to showing code
|
||||
if echo == nil then echo = "true" end
|
||||
|
||||
local result = {}
|
||||
|
||||
-- Handle code display
|
||||
if echo ~= "false" then
|
||||
local codeBlock = pandoc.CodeBlock(spec, {class = "json"})
|
||||
|
||||
if codeFold == "true" or codeFold == "show" then
|
||||
-- Wrap in collapsible details/summary
|
||||
local openAttr = ""
|
||||
if codeFold == "show" then
|
||||
openAttr = " open"
|
||||
end
|
||||
|
||||
local foldedCode = pandoc.RawBlock('html', string.format([[
|
||||
<details%s>
|
||||
<summary>Click to expand code</summary>
|
||||
]], openAttr))
|
||||
|
||||
table.insert(result, foldedCode)
|
||||
table.insert(result, codeBlock)
|
||||
table.insert(result, pandoc.RawBlock('html', '</details>'))
|
||||
else
|
||||
-- Show code normally
|
||||
table.insert(result, codeBlock)
|
||||
end
|
||||
end
|
||||
|
||||
-- Create the HTML output for the visualization
|
||||
local html = string.format([[
|
||||
<div id="%s"></div>
|
||||
<script type="text/javascript">
|
||||
vegaEmbed('#%s', %s, {"actions": true});
|
||||
</script>
|
||||
]], divId, divId, spec)
|
||||
|
||||
table.insert(result, pandoc.RawBlock('html', html))
|
||||
|
||||
return result
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user