Implements cookie consent using vanilla-cookieconsent v3 to comply with
GDPR requirements. Analytics scripts are blocked until user consent is
obtained.
## Changes
**Library Integration**
- Added `vanilla-cookieconsent@3.1.0` to `_config.yml` third-party
libraries with SRI hashes
- Created `_scripts/cookie-consent-setup.js` with consent modal and
settings configuration
- Added CSS/JS includes in `_includes/head.liquid` and
`_includes/scripts.liquid`
**Analytics Blocking**
- Modified analytics scripts in `scripts.liquid` and
`distill_scripts.liquid` to use conditional `type="text/plain"
data-category="analytics"` when consent is disabled
- Blocks Google Analytics, Cronitor, Pirsch, and OpenPanel until consent
granted
- Library automatically converts blocked scripts to executable on user
acceptance
**Configuration**
- Added `enable_cookie_consent` flag (default: `false`)
- Cookie categories: `necessary` (always on), `analytics` (optional)
- 182-day cookie expiration, auto-clear on rejection
## Implementation
```liquid
{% if site.enable_cookie_consent %}
<script type="text/plain" data-category="analytics" async src="...gtag.js"></script>
{% else %}
<script async src="...gtag.js"></script>
{% endif %}
```
Enable in `_config.yml`:
```yaml
enable_cookie_consent: true
```
## Screenshots
**Consent Modal**

**Settings Modal**

> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `cdn.jsdelivr.net`
> - Triggering command: `/usr/bin/curl curl -s REDACTED` (dns block)
> - `cookieconsent.orestbida.com`
> - Triggering command:
`/home/REDACTED/work/_temp/ghcca-node/node/bin/node
/home/REDACTED/work/_temp/ghcca-node/node/bin/node --enable-source-maps
/home/REDACTED/work/_temp/copilot-developer-action-main/dist/index.js`
(dns block)
> - `medium.com`
> - Triggering command: `/usr/local/bin/ruby ruby
/usr/local/bundle/bin/bundle exec jekyll serve --watch --port=8080
--host=0.0.0.0 --livereload --verbose --trace --force_polling s
6_64-linux /etc/locale.gen by/backward -binutils_2.44-3grep .deb eb
/systemd-sysctl` (dns block)
> - `publish.twitter.com`
> - Triggering command: `/usr/local/bin/ruby ruby
/usr/local/bundle/bin/bundle exec jekyll serve --watch --port=8080
--host=0.0.0.0 --livereload --verbose --trace --force_polling lude
lude/ruby-4.0.0//run/containerd/io.containerd.runtime.v2.task/moby/a4760212ce4eda97e32b6dfa4d3ea/usr/sbin/iptables
r/runc-log.json f8_range lude r-strong E r/wc7in709a54d7hshow` (dns
block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/alshedivat/al-folio/settings/copilot/coding_agent)
(admins only)
>
> </details>
<!-- START COPILOT ORIGINAL PROMPT -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>GDPR compliant cookie consent dialog</issue_title>
> <issue_description>Hi,
>
> since I am from Europe and want my site to be accessed by EU citizens
I need to ask users if they are ok with the use of cookies. Adding a
dialogue by default that that asks the user before any cookies /
localStorage are used would be nice.
>
> I have integrated the dialog from
[https://www.cookieconsent.com/](https://www.cookieconsent.com/) on [my
website](http://hschwane.github.io) and am happy to file a PR if you are
interested. However It is not shown directly at the top, but below the
menu bar for some reason. Not sure how to fix that.
> </issue_description>
>
> <agent_instructions>Implement this using cookie consent dialog from
https://github.com/orestbida/cookieconsent. The documentation is
available at
https://cookieconsent.orestbida.com/essential/getting-started.html.</agent_instructions>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> <comment_new><author>@alshedivat</author><body>
> @hschwane, thanks for pointing this out. It's would be great if you
could send a PR.
>
> To answer your question about positioning, the menu bar has the
absolute position at the top of the page and keeps moving with
scrolling. You can change that behavior in `_config.yml` by setting
`navbar_fixed: false` (see [line
27](https://github.com/alshedivat/al-folio/blob/master/_config.yml#L27)).
If you send a PR with basic functionality, I can help with adjusting the
styles a bit. Thanks!</body></comment_new>
> <comment_new><author>@alshedivat</author><body>
> Just catching up on this discussion.
>
> @hschwane, thanks for providing an implementation based on
`ihavecookies`! I looked through alshedivat/al-folio#223. It seems like
to be able to correctly (un)block different types of cookies (all of
which are third-party cookies) requires adding quite a bit of extra
JavaScript (including adding it directly to posts or pages in some
cases, e.g., when posts embed youtube videos or other external content).
This approach will put some extra burden on contributors and maintainers
of al-folio down the line.
>
> By the way, the dialog from https://www.cookieconsent.com/ is similar
in that sense as it requires to manually add ALL scripts that use
cookies. So, if someone contributes a new feature to al-folio that uses
cookies, the contributor would have to go and update the cookie consent
dialog as well (or edit quite a bit of JS if `ihavecookies` is used).
>
> Thinking about this more, I currently see only three options:
> 1. If we want to have cookie consent as a core part of al-folio (which
can be easily enabled or disabled), it needs to be a service that
automatically identifies and blocks cookies, without putting an extra
burden on the contributors or maintainers. The hosted version of [Cookie
Consent by Osano](https://www.osano.com/features/consent-management) is
an example.
> 2. Another option is to provide a very minimalistic cookie consent
dialog which simply says that the website uses cookies, without an
option to opt-in or opt-out (e.g., see the open-source edition of
[Osano](https://www.osano.com/cookieconsent/download/)).
> 3. Finally, not have cookie consent as part of al-folio, and make the
user responsible for figuring out whether they need a consent dialog and
which service to use.
>
> Let me know what you think.</body></comment_new>
> <comment_new><author>@alshedivat</author><body>
> the best way to add GDPR compliant cookie consent is using
https://github.com/orestbida/cookieconsent</body></comment_new>
> </comments>
>
</details>
> **Custom agent used: customization_agent**
> Expert customization assistant for the al-folio Jekyll academic
website template
<!-- START COPILOT CODING AGENT SUFFIX -->
- Fixesalshedivat/al-folio#199
<!-- START COPILOT CODING AGENT TIPS -->
---
✨ Let Copilot coding agent [set things up for
you](https://github.com/alshedivat/al-folio/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.
---------
Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: george-gca <31376482+george-gca@users.noreply.github.com>
Co-authored-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This pull request significantly expands and clarifies the documentation
for the al-folio Jekyll theme, focusing on improved file structure
explanations, enhanced quick reference guides, and the addition of a
comprehensive analytics setup guide. The changes make it easier for
users and contributors to understand the project organization, available
features, and configuration options, especially regarding CV formats,
teaching pages, and analytics integration.
**Key documentation and structure improvements:**
*Expanded file and collection structure:*
- The file structure documentation in
`.github/agents/customize.agent.md` and `.github/agents/docs.agent.md`
now details all major directories, including new and existing
collections such as `_books/`, `_teachings/`, `_scripts/`, `_plugins/`,
and expanded `assets/` subdirectories. It also covers new configuration
and utility files, making it easier for users to locate and understand
the purpose of each file or folder.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L24-R66)
[[2]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L17-R58)
*Documentation and quick reference enhancements:*
- The quick reference table in `.github/agents/customize.agent.md` has
been updated to include new actions like adding teaching pages, setting
up analytics, improving SEO, and ensuring accessibility, with more
precise documentation links.
- The documentation map now lists all major guides (e.g.,
`QUICKSTART.md`, `INSTALL.md`, `TROUBLESHOOTING.md`, `ACCESSIBILITY.md`,
`ANALYTICS.md`, `SEO.md`), providing a clearer overview of available
resources.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L58-R110)
[[2]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L17-R58)
**Feature and configuration documentation updates:**
*CV/resume format guidance:*
- The CV documentation now clarifies that users can maintain both
RenderCV and JSONResume formats simultaneously, with clear instructions
on switching between them and deleting unused files if desired.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L139-R185)
[[2]](diffhunk://#diff-52f2a9488bfe4177d1f1d01120859dad0b3e2d087283ded68f72d47b4f183391L291-R291)
*Teaching pages and new collections:*
- Adds documentation for the new `_teachings/` collection, including
required frontmatter and support for course materials, as well as
updates to enable/disable teaching and books pages via `_config.yml`.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L180-R252)
[[2]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L24-R66)
*Analytics integration:*
- Introduces a new `ANALYTICS.md` guide with detailed setup instructions
for Google Analytics, privacy-friendly alternatives (Plausible, Pirsch,
Openpanel, GoAccess), GDPR considerations, and a comparison table to
help users choose the right analytics provider.
- The configuration documentation now references analytics setup and
related configuration options.
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L180-R252)
[[2]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L479-R550)
These updates collectively make the documentation more comprehensive,
actionable, and user-friendly for both new and advanced users.
**References:**
[[1]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L24-R66)
[[2]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L58-R110)
[[3]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L139-R185)
[[4]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L180-R252)
[[5]](diffhunk://#diff-15864f2655921f50a97689076e3b8feba0da320463750845be6a76eb2e30bfe4L479-R550)
[[6]](diffhunk://#diff-961a46180ce568ce43c20bf7129dc5e4926a9aa4e0d7bc19926ca5ee3ff95cd0L17-R58)
[[7]](diffhunk://#diff-0967e840631a541bb95e057e1c6d4884274cf56d5a217d7fee2eb7223b6b4c0dR1-R268)
[[8]](diffhunk://#diff-52f2a9488bfe4177d1f1d01120859dad0b3e2d087283ded68f72d47b4f183391L291-R291)
---------
Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Partially fixes issue #3256 by updating SASS syntax in main SCSS files.
To fully address the issue, FontAwesome should be updated to `v7.x` and
Tabler to `v3.30` or higher (see Tabler fix
[here](https://github.com/tabler/tabler-icons/pull/1256)), where the
SCSS has been fixed.
---------
Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: George Araújo <george.gcac@gmail.com>
Fixes#2787 as an alternative to #2969. It was getting too cumbersome to
have 2 different data sources for CV and also a lot of different layout
files, so I decided to unify them all.
Main changes:
- synchronized the information inside RenderCV (`_data/cv.yml`) and
JSONResume (`assets/json/resume.json`)
- unified layout files for CV information
- added the option to set the "data source" in the CV page
---------
Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
### Description
This PR adds a Google Calendar integration feature as described in issue
#872. Users can embed their own calendar using an iframe configured via
`_config.yml`, and the calendar is toggleable through a responsive
button. This component is styled to visually blend into the theme and
supports responsive display across desktop and mobile.
### Changes
- Added `calendar.liquid` in `_includes`
- Modified `about.md` to include the toggleable calendar block
- Introduced `calendar` config section in `_config.yml`
- Appended calendar-related styles in `_sass/_base.scss`
### Configuration
To enable this feature, add the following to `_config.yml`:
```yaml
calendar:
enabled: true
calendar_id: your_calendar_id@group.calendar.google.com
timezone: UTC
style: "border:0; width:100%; height:600px;"
---------
Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: dodo <349507644@qq.com>
Co-authored-by: George <31376482+george-gca@users.noreply.github.com>
Co-authored-by: George Araújo <george.gcac@gmail.com>
Implements the course schedule feature requested in issue
#[2258](https://github.com/alshedivat/al-folio/issues/2258).
This PR adds a new course schedule feature to the al-folio theme,
allowing academics to easily create and display structured course
information.
**Changes:**
- Added a `courses` collection to organize and display academic courses
- Created course layout and display templates with responsive design
- Implemented organization by year and term with automatic sorting
- Added support for weekly schedule with topics and course materials
- Simplified documentation with a README for course creation
This feature makes it easier for academics to showcase their teaching
materials with a consistent, organized display of course schedules,
helping users create professional teaching pages without custom
implementation.
---------
Signed-off-by: George Araújo <george.gcac@gmail.com>
Co-authored-by: George Araújo <george.gcac@gmail.com>
## Description
This PR makes the URLs for external services used on the repository page
configurable in `_config.yml`. This allows users to self-host these
services for better reliability, privacy, and customization.
## Changes
- Added `external_services` configuration section in `_config.yml` with:
- `github_readme_stats_url` (default:
`https://github-readme-stats.vercel.app`)
- `github_profile_trophy_url` (default:
`https://github-profile-trophy.vercel.app`)
- Updated repository template files to use configurable URLs:
- `_includes/repository/repo_user.liquid`
- `_includes/repository/repo.liquid`
- `_includes/repository/repo_trophies.liquid`
- Added documentation in `CUSTOMIZE.md` explaining:
- Why self-hosting is recommended (default services may have
availability issues)
- How to configure custom service URLs
- Links to the service repositories for deployment instructions
## Resolves
Resolves#3388 - This makes it possible to configure self-hosted
versions of these services, giving users full control over the external
services used for displaying GitHub statistics and trophies.
## Testing
- Verified that default configuration still works with original service
URLs
- Confirmed that URLs are properly interpolated in all template files
- Documentation clearly explains the configuration options
This PR fixes a recurring typo in multiple Liquid templates where the
Bootstrap class `cl-sm` is used instead of `col-sm`.
Because of this typo, the `col-sm` styling was not being applied. All
instances have been corrected.
Fixes issue #3243
Add CV PDF link to social icons
- Added CV icon to social media links section
- CV appears after LinkedIn icon in the contact section
- Uses academicons CV symbol for consistent academic styling
- Links to `/assets/pdf/CV_Schirren.pdf` and opens in new tab
- Updated `_includes/social.liquid` to handle `cv_pdf` field
- Updated `_data/socials.yml` with CV configuration
- Updated `_scripts/search.liquid.js` with cv search functionality
Partially addresses issue #3280.
Currently, the RSS feed icon in the socials section will show whenever
`rss_icon` in `data/_socials.yml` has a value --- **even if that value
is `false`**.
Unlike the other social settings, which are empty by default, for
`rss_icon` the default setting is `true`.
So it makes sense that a user might expect `rss_icon: false` to disable
said icon.
This PR just adds a check if the value is `false` and hides the icon if
so.
This reverts PR #2962. The inline script here is exactly the same as the
`/assets/js/google-analytics-setup.js` sourced on the following line, so
Google Analytics is being triggered twice.
It seems that #2962 originally added this because liquid templating of
the setup script didn't work (#3095). However, this was then properly
fixed in #3117.
Currently, the `site.giscus.theme` option is ignored because
`giscus.liquid` always computes the theme as light/dark based on the
current site theme. This PR allows users to configure separate light and
dark giscus themes in `_config.yml`, which will support dynamic updates
when switching between light, dark, or system themes.
Fixes#3269
## Description
This pull request adds support for Academia.edu profiles to the al-folio
social media integrations. Academia.edu is widely used by academics to
share and discover research,.
The changes are minimal and well-contained:
1. Added configuration options in socials.yml for Academia.edu with
organization and username fields
2. Updated social.liquid to handle the new social integration using the
Academicons font which already includes support for Academia.edu
## Changes
The implementation uses Academicons, which already includes the
Academia.edu icon (`ai-academia`), making this addition a natural fit
for the theme.
Unlike some other social media links that only require a single ID or
URL, Academia.edu profiles include both an organization (subdomain) and
a username in the format:
`https://[organization].academia.edu/[username]`. The implemented
solution supports this pattern by adding two parameters in the
socials.yml file.
## Why this is important
Academia.edu is a popular platform used by millions of researchers
worldwide to share their work. Adding support for it in the al-folio
theme aligns with the theme's academic focus and enhances its utility
for scholarly users. Many academics maintain both personal websites and
Academia.edu profiles, and being able to link between them provides
better visibility for their research.
The Academicons font already includes support for Academia.edu, so
adding this feature is a natural extension that makes use of existing
resources in the theme.
## Testing
The changes have been tested locally with a sample Academia.edu profile,
and the icon displays correctly alongside other social media icons. The
changes are minimal and don't affect any existing functionality.
## Screenshot
<img width="991" alt="image"
src="https://github.com/user-attachments/assets/15468b67-3002-44ce-aa25-22bc10766664"
/>
Hi,
I noticed some weird behavior when I turned dark mode off (some of the
text seemed to disappear, it became white :) )
I traced it to: {% if site.enable_darkmode %} in head.liquid
where some darkmode features are place before the if statement.
When putting it inside the if statement then the weird behavior was
solved; see the pull request here :)
Cheers,
Jan
This PR adds a few stylistic improvements to the distill-style blog
posts:
- Update distill blog post example to showcase sidenotes as an
alternative to styles in PR #3077
- Showcase equations in sidenotes (closes#1242)
- Add `overrides.js` to match footnotes and citation styles with global
theme styling
- Add "related posts" sections if enabled to distill style posts
- Add "giscus" section if enabled to distill style posts
https://github.com/user-attachments/assets/b19a9cd9-779d-4d89-a4fb-eb14fb384480
The author of github-readme-stats uses the non-standard code "cn" for
simplified Chinese, see
[here](https://github.com/anuraghazra/github-readme-stats?tab=readme-ov-file#available-locales).
While for traditional Chinese the author only provides "zh-tw". The
github-readme-stats functions on repo page will break if the user sets
the site language to ALL variants of Chinese except for zh-tw. This hack
is to make all sub-variants of simplified Chinese fall back to "cn" and
all sub-variants of traditional Chinese fall back to "zh-tw".
This patch fixes the problem and has been tested locally & with GitHub
pages.
Implementation of Google tag ID to correctly getting tracked requires
further modification in addition to the one line script in the
`_includes/scripts.liquid` file as
```
<script async src="https://www.googletagmanager.com/gtag/js?id={{ site.google_analytics }}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', '{{ site.google_analytics }}');
</script>
```
I have made the changes and tested it out on my personal webpage to
ensure the tracking in analytics dashboard.
Fixes#2890
With the recent updates (v0.13.0) the email badge (social) does not
contain the email anymore.
Some link generations in social.liquid used the old schema
Also updated the handling for mastodon to be aligned to the other social
badges.
Closes#930.
We already had classes for this kind of feature, but it was used
specifically for repository information. Just renamed the classes so it
is clear how they can be used.
To use them with markdown, just do it like this:
```markdown
{: .only-light}
{: .only-dark}
```
and with html:
```html
<img
class="only-light"
src="assets/img/prof_pic_color.png"
>
<img
class="only-dark"
src="assets/img/prof_pic.jpg"
>
```
Signed-off-by: George Araújo <george.gcac@gmail.com>
Added support for multiple image galleries, and created a sample post
showing how to enable and use them.
---------
Signed-off-by: George Araújo <george.gcac@gmail.com>
Fix#2876
Weirdly enough, we already escape the title a few lines above the
changed one, but had to escape it again here.
Signed-off-by: George Araújo <george.gcac@gmail.com>
This PR modifies
- `_config.yml` to rename `bluesky_url` into `bluesky_id`
- `_includes/social.liquid` to handle the renaming in the display of
social media icons
I tested on my Github page and it worked correctly. Then, copied here.
Issue: Blog page navigation extends layout of the page in small screens.
Fixes: #2841