+ {{ title }} +
++ {{ excerpt }} +
++ {{ excerpt }} +
++ + {{ segment.text }} + {{ segment.text }} + +
+ + +{{ $t('blog.atproto.no_comments_yet') }}
+
+ {{ $t('tagline') }}
+ No posts found.
` tag.
+
+When you _do_ want to insert a `
` break tag using Markdown, you
+end a line with two or more spaces, then type return.
+
+### Headers
+
+Markdown supports two styles of headers, [Setext] [1] and [atx] [2].
+
+Optionally, you may "close" atx-style headers. This is purely
+cosmetic -- you can use this if you think it looks better. The
+closing hashes don't even need to match the number of hashes
+used to open the header. (The number of opening hashes
+determines the header level.)
+
+### Blockquotes
+
+Markdown uses email-style `>` characters for blockquoting. If you're
+familiar with quoting passages of text in an email message, then you
+know how to create a blockquote in Markdown. It looks best if you hard
+wrap the text and put a `>` before every line:
+
+> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+>
+> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+> id sem consectetuer libero luctus adipiscing.
+
+Markdown allows you to be lazy and only put the `>` before the first
+line of a hard-wrapped paragraph:
+
+> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+
+> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+> id sem consectetuer libero luctus adipiscing.
+
+Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
+adding additional levels of `>`:
+
+> This is the first level of quoting.
+>
+> > This is nested blockquote.
+>
+> Back to the first level.
+
+Blockquotes can contain other Markdown elements, including headers, lists,
+and code blocks:
+
+> ## This is a header.
+>
+> 1. This is the first list item.
+> 2. This is the second list item.
+>
+> Here's some example code:
+>
+> return shell_exec("echo $input | $markdown_script");
+
+Any decent text editor should make email-style quoting easy. For
+example, with BBEdit, you can make a selection and choose Increase
+Quote Level from the Text menu.
+
+### Lists
+
+Markdown supports ordered (numbered) and unordered (bulleted) lists.
+
+Unordered lists use asterisks, pluses, and hyphens -- interchangably
+-- as list markers:
+
+- Red
+- Green
+- Blue
+
+is equivalent to:
+
+- Red
+- Green
+- Blue
+
+and:
+
+- Red
+- Green
+- Blue
+
+Ordered lists use numbers followed by periods:
+
+1. Bird
+2. McHale
+3. Parish
+
+It's important to note that the actual numbers you use to mark the
+list have no effect on the HTML output Markdown produces. The HTML
+Markdown produces from the above list is:
+
+If you instead wrote the list in Markdown like this:
+
+1. Bird
+1. McHale
+1. Parish
+
+or even:
+
+3. Bird
+1. McHale
+1. Parish
+
+you'd get the exact same HTML output. The point is, if you want to,
+you can use ordinal numbers in your ordered Markdown lists, so that
+the numbers in your source match the numbers in your published HTML.
+But if you want to be lazy, you don't have to.
+
+To make lists look nice, you can wrap items with hanging indents:
+
+- Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+ Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+ viverra nec, fringilla in, laoreet vitae, risus.
+- Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+ Suspendisse id sem consectetuer libero luctus adipiscing.
+
+But if you want to be lazy, you don't have to:
+
+- Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+ Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+ viverra nec, fringilla in, laoreet vitae, risus.
+- Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+ Suspendisse id sem consectetuer libero luctus adipiscing.
+
+List items may consist of multiple paragraphs. Each subsequent
+paragraph in a list item must be indented by either 4 spaces
+or one tab:
+
+1. This is a list item with two paragraphs. Lorem ipsum dolor
+ sit amet, consectetuer adipiscing elit. Aliquam hendrerit
+ mi posuere lectus.
+
+ Vestibulum enim wisi, viverra nec, fringilla in, laoreet
+ vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
+ sit amet velit.
+
+2. Suspendisse id sem consectetuer libero luctus adipiscing.
+
+It looks nice if you indent every line of the subsequent
+paragraphs, but here again, Markdown will allow you to be
+lazy:
+
+- This is a list item with two paragraphs.
+
+ This is the second paragraph in the list item. You're
+
+ only required to indent the first line. Lorem ipsum dolor
+ sit amet, consectetuer adipiscing elit.
+
+- Another item in the same list.
+
+To put a blockquote within a list item, the blockquote's `>`
+delimiters need to be indented:
+
+- A list item with a blockquote:
+
+ > This is a blockquote
+ > inside a list item.
+
+To put a code block within a list item, the code block needs
+to be indented _twice_ -- 8 spaces or two tabs:
+
+- A list item with a code block:
+
+
+
+### Code Blocks
+
+Pre-formatted code blocks are used for writing about programming or
+markup source code. Rather than forming normal paragraphs, the lines
+of a code block are interpreted literally. Markdown wraps a code block
+in both `` and `
` tags.
+
+To produce a code block in Markdown, simply indent every line of the
+block by at least 4 spaces or 1 tab.
+
+This is a normal paragraph:
+
+ This is a code block.
+
+Here is an example of AppleScript:
+
+ tell application "Foo"
+ beep
+ end tell
+
+A code block continues until it reaches a line that is not indented
+(or the end of the article).
+
+Within a code block, ampersands (`&`) and angle brackets (`<` and `>`)
+are automatically converted into HTML entities. This makes it very
+easy to include example HTML source code using Markdown -- just paste
+it and indent it, and Markdown will handle the hassle of encoding the
+ampersands and angle brackets. For example, this:
+
+
+
+Regular Markdown syntax is not processed within code blocks. E.g.,
+asterisks are just literal asterisks within a code block. This means
+it's also easy to use Markdown to write about Markdown's own syntax.
+
+```
+tell application "Foo"
+ beep
+end tell
+```
+
+## Span Elements
+
+### Links
+
+Markdown supports two style of links: _inline_ and _reference_.
+
+In both styles, the link text is delimited by [square brackets].
+
+To create an inline link, use a set of regular parentheses immediately
+after the link text's closing square bracket. Inside the parentheses,
+put the URL where you want the link to point, along with an _optional_
+title for the link, surrounded in quotes. For example:
+
+This is [an example](http://example.com/) inline link.
+
+[This link](http://example.net/) has no title attribute.
+
+### Emphasis
+
+Markdown treats asterisks (`*`) and underscores (`_`) as indicators of
+emphasis. Text wrapped with one `*` or `_` will be wrapped with an
+HTML `` tag; double `*`'s or `_`'s will be wrapped with an HTML
+`` tag. E.g., this input:
+
+_single asterisks_
+
+_single underscores_
+
+**double asterisks**
+
+**double underscores**
+
+### Code
+
+To indicate a span of code, wrap it with backtick quotes (`` ` ``).
+Unlike a pre-formatted code block, a code span indicates code within a
+normal paragraph. For example:
+
+Use the `printf()` function.
+
+
diff --git a/app/pages/blog/index.vue b/app/pages/blog/index.vue
new file mode 100644
index 0000000000..22e4ac73e7
--- /dev/null
+++ b/app/pages/blog/index.vue
@@ -0,0 +1,52 @@
+
+
+
+
+ {{ $t('blog.heading') }}
+
+
+
+
Blog post content here.
' }, + }) + const results = await runAxe(component) + expect(results.violations).toEqual([]) + }) + }) + + describe('BlueskyComment', () => { + it('should have no accessibility violations', async () => { + const component = await mountSuspended(BlueskyComment, { + props: { + comment: { + uri: 'at://did:plc:2gkh62xvzokhlf6li4ol3b3d/app.bsky.feed.post/3mcg7k75fdc2k', + cid: 'bafyreigincphooxt7zox3blbocf6hnczzv36fkuj2zi5iuzpjgq6gk6pju', + author: { + did: 'did:plc:2gkh62xvzokhlf6li4ol3b3d', + handle: 'patak.dev', + displayName: 'patak', + avatar: + 'https://cdn.bsky.app/img/avatar/plain/did:plc:2gkh62xvzokhlf6li4ol3b3d/bafkreifgzl4e5jqlakd77ajvnilsb5tufsv24h2sxfwmitkzxrh3sk6mhq@jpeg', + }, + text: 'our kids will need these new stories, thanks for writing this Daniel', + createdAt: '2026-01-14T23:22:05.257Z', + likeCount: 13, + replyCount: 0, + repostCount: 0, + replies: [], + }, + depth: 0, + }, + }) + const results = await runAxe(component) + expect(results.violations).toEqual([]) + }) + }) + + describe('BlueskyComments', () => { + it('should have no accessibility violations', async () => { + const component = await mountSuspended(BlueskyComments, { + props: { + postUri: 'at://did:plc:jbeaa5kdaladzwq3r7f5xgwe/app.bsky.feed.post/3mcg6svsgsm2k', + }, + }) + const results = await runAxe(component) + expect(results.violations).toEqual([]) + }) + }) + + describe('BlogPostListCard', () => { + it('should have no accessibility violations', async () => { + const component = await mountSuspended(BlogPostListCard, { + props: { + authors: [{ name: 'Daniel Roe', blueskyHandle: 'danielroe.dev' }], + title: 'Building Accessible Vue Components', + topics: ['accessibility', 'vue'], + excerpt: 'A guide to building accessible components in Vue.js applications.', + published: '2024-06-15', + path: 'alpha-release', + index: 0, + }, + }) + const results = await runAxe(component) + expect(results.violations).toEqual([]) + }) + }) + + describe('BlogPostFederatedArticles', () => { + it('should have no accessibility violations', async () => { + const component = await mountSuspended(BlogPostFederatedArticles, { + props: { + headline: 'Read more on Bluesky', + articles: [ + { + url: 'https://example.com/post-1', + title: 'Federated Testing Patterns', + description: 'How to keep accessibility checks simple and maintainable.', + authorHandle: 'danielroe.dev', + }, + { + url: 'https://example.com/post-2', + title: 'Composable Data in Vue', + description: 'Practical patterns for data composition in Vue components.', + authorHandle: 'salma.dev', + }, + ], + }, + }) + const results = await runAxe(component) + expect(results.violations).toEqual([]) + }) + }) + describe('PackageReplacement', () => { it('should have no accessibility violations for native replacement', async () => { const component = await mountSuspended(PackageReplacement, { diff --git a/test/unit/a11y-component-coverage.spec.ts b/test/unit/a11y-component-coverage.spec.ts index 0f18a000e7..f6f6ea845a 100644 --- a/test/unit/a11y-component-coverage.spec.ts +++ b/test/unit/a11y-component-coverage.spec.ts @@ -23,6 +23,7 @@ import { fileURLToPath } from 'node:url' */ const SKIPPED_COMPONENTS: Record