diff --git a/packages/comment-widget/src/commenter-ua-bar.ts b/packages/comment-widget/src/commenter-ua-bar.ts
new file mode 100644
index 0000000..4fcb635
--- /dev/null
+++ b/packages/comment-widget/src/commenter-ua-bar.ts
@@ -0,0 +1,93 @@
+import { css, html, LitElement } from 'lit';
+import { property, state } from 'lit/decorators.js';
+import type { UAParser } from 'ua-parser-js';
+import baseStyles from './styles/base';
+
+const OS_ICON_MAP = {
+ Windows: 'i-logos:microsoft-windows-icon',
+ macOS: 'i-logos:apple',
+ Linux: 'i-logos:linux-tux',
+ Android: 'i-logos:android-icon',
+ iOS: 'i-logos:apple',
+ 'Chrome OS': 'i-logos:chrome',
+ Arch: 'i-logos:archlinux',
+ Manjaro: 'i-logos:manjaro',
+ Ubuntu: 'i-logos:ubuntu',
+ Fedora: 'i-logos:fedora',
+};
+
+const BROWSER_ICON_MAP = {
+ Chrome: 'i-logos:chrome',
+ 'Mobile Chrome': 'i-logos:chrome',
+ 'Chrome WebView': 'i-logos:chrome',
+ Firefox: 'i-logos:firefox',
+ 'Mobile Firefox': 'i-logos:firefox',
+ Safari: 'i-logos:safari',
+ 'Mobile Safari': 'i-logos:safari',
+ Edge: 'i-logos:microsoft-edge',
+ 'Edge WebView': 'i-logos:microsoft-edge',
+ 'Edge WebView2': 'i-logos:microsoft-edge',
+ Opera: 'i-logos:opera',
+};
+
+export class CommenterUABar extends LitElement {
+ @property({ type: String })
+ ua: string = '';
+
+ @state()
+ parser: UAParser | undefined;
+
+ getOSIcon(os?: string) {
+ return OS_ICON_MAP[os as keyof typeof OS_ICON_MAP];
+ }
+
+ getBrowserIcon(browser?: string) {
+ return BROWSER_ICON_MAP[browser as keyof typeof BROWSER_ICON_MAP];
+ }
+
+ override connectedCallback(): void {
+ super.connectedCallback();
+ this.init();
+ }
+
+ async init() {
+ const { UAParser } = await import('ua-parser-js');
+ this.parser = new UAParser(this.ua);
+ }
+
+ protected override render() {
+ if (!this.parser) {
+ return html``;
+ }
+
+ const osIcon = this.getOSIcon(this.parser.getOS().name);
+ const browserIcon = this.getBrowserIcon(this.parser.getBrowser().name);
+
+ return html`
+
+ ${osIcon ? html`` : ''}
+ ${this.parser.getOS().name}
+
+
+ ${browserIcon ? html`` : ''}
+ ${this.parser.getBrowser().name}
+
+
`;
+ }
+
+ static override styles = [
+ ...baseStyles,
+ css`
+ @unocss-placeholder;
+ `,
+ ];
+}
+
+customElements.get('commenter-ua-bar') ||
+ customElements.define('commenter-ua-bar', CommenterUABar);
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'commenter-ua-bar': CommenterUABar;
+ }
+}
diff --git a/packages/comment-widget/src/reply-item.ts b/packages/comment-widget/src/reply-item.ts
index d586400..2b18e56 100644
--- a/packages/comment-widget/src/reply-item.ts
+++ b/packages/comment-widget/src/reply-item.ts
@@ -122,6 +122,7 @@ export class ReplyItem extends LitElement {
.approved=${this.reply?.spec.approved}
.breath=${this.isQuoteReplyHovered}
.userWebsite=${this.reply?.spec.owner.annotations?.website}
+ .ua=${this.reply?.spec.userAgent}
>