Repository navigation
refactor(links): standardize external links site-wide #36
Description
Decision update
We have changed the scope of this issue: the Mastodon feed integration is no longer wanted and must be removed again from the implementation branch / PR #37.
The remaining goal is the site-wide external-link behavior that was implemented together with the Mastodon work.
Goal
Introduce one consistent, reusable rule for external links across the entire website:
- every external HTTP(S) link opens with
target="_blank" - every such link also includes
rel="noopener noreferrer" - internal links stay in the same tab
- same-site absolute URLs for
https://oklabflensburg.de/...are treated as internal - Nuxt Content / Markdown links follow the same rule centrally
- localized internal routing, query strings and fragments remain intact
Canonical implementation direction
Keep one shared external-link detector, for example shared/utils/links.ts, based on the canonical site.url origin.
Use a reusable component such as app/components/SiteLink.vue for ordinary Vue links where appropriate, and make app/components/content/ProseA.vue use the same rule for Nuxt Content Markdown links.
Do not scatter unrelated target="_blank" checks across components if a shared helper/component can own the behavior.
External-link rules
External examples:
- GitHub repositories / organization pages
- project websites hosted on other domains
- Code for Germany
- OpenStreetMap
- Mastodon profile links that already exist elsewhere on the site
- source URLs and other external resources
Required output:
<a href="https://example.org" target="_blank" rel="noopener noreferrer">…</a>Internal examples:
/projekte/mitmachen- localized Nuxt routes
https://oklabflensburg.de/projekte
These must remain same-tab navigation.
Preserve special rel tokens where semantically required, e.g. Mastodon identity verification via rel="me"; combine them with noopener noreferrer rather than replacing them.
Mastodon feed rollback / out of scope
Remove all code that was added solely to show latest Mastodon posts on the homepage. In particular, PR #37 should no longer contain the Mastodon feed feature, its API/client plumbing, cache, fixtures, feed-specific UI, docs, configuration or dependencies.
Expected removals include, where they exist only for that feature:
app/components/MastodonFeed.vueapp/components/MastodonPostCard.vueserver/api/social/mastodon.get.tsserver/utils/mastodon.tsshared/types/mastodon.tsdocs/mastodon.md- Mastodon feed-specific tests / fixtures / screenshots
- Mastodon feed-specific env/runtime config
- dependencies added only for Mastodon parsing/testing
- homepage feed layout/copy added only for the feed
The existing normal profile link to https://norden.social/@oklabflensburg may remain as an ordinary external social link and should follow the new external-link rule.
Do not add a Mastodon API feed, server-side fetcher, embed, cache, media proxy or homepage social-post section as part of this issue.
Repository-wide audit
At minimum review links in:
app/components/content/ProseA.vueAppHeader.vueAppFooter.vueEditorialPage.vueEventCard.vueMeetingSection.vueTeamList.vueLegalDetails.vue- error page
- project detail pages
- project cards / blog cards if they render external URLs
- source / GitHub / project website links
Internal Nuxt navigation should continue to use NuxtLink / locale-aware routing.
Accessibility / security
- never emit
target="_blank"withoutnoopener noreferrer - keep accessible link names meaningful
- if a reusable accessible hint for new-tab behavior already exists and is unobtrusive, it may remain
- do not regress keyboard navigation or focus handling
- preserve
rel="me"where needed for identity verification
Tests
Keep/add focused regression tests for the link behavior only:
- external Markdown link =>
_blank+noopener noreferrer - internal Markdown link => same tab / Nuxt navigation
- same-site absolute URL => internal
- external GitHub / project / source link =>
_blank - query strings and fragments preserved
- existing
rel="me"is preserved alongside safe rel values - DE/DA/EN navigation still works
Remove tests that only exist for the Mastodon feed/API/content parsing/cache/fallback.
Acceptance criteria
- All external HTTP(S) links consistently open in a new tab.
- Every
_blanklink includesnoopener noreferrer. - Existing semantic rel values such as
meare preserved where required. - Internal links and same-origin absolute links remain same-tab.
- Nuxt Content links use the same central rule.
- Localized internal routing, queries and fragments are preserved.
- No duplicate external-link detection logic is introduced.
- Mastodon feed/API/cache/components/config/docs/tests/fixtures/screenshots introduced by PR refactor(links): standardize external link behavior #37 are removed.
- The normal Mastodon profile link may remain as a regular external social link.
- No new Mastodon feed functionality remains anywhere in the branch.
- Focused link regression tests pass.
-
pnpm lint,pnpm typecheck,pnpm test,pnpm buildand relevant E2E tests pass. - Website CI and CodeQL are green on the revised PR.
Activity
[-]feat(social): show latest Mastodon posts on homepage[/-][+]refactor(links): standardize external links site-wide[/+]