wafir
v0.1.0
Published
A powerful, framework-agnostic UI widget library built with Lit & TypeScript.
Maintainers
Readme
Wafir - The Web App Feedback and Issue Reporter
Wafir is a lightweight feedback and issue reporting tool that seamlessly connects input from users and testers to your GitHub-based development workflow. It captures user input, screenshots, console logs, and essential browser telemetry to accelerate debugging. See details at https://bps-consulting.github.io/wafir/.
What's in this Repo
This repository contains everything needed to build, use, and support Wafir. You don't need to clone the repo to use Wafir: simply get the widget code and add it to your web application as described in the Quickstart Guide.
The repo includes source code for the following:
- Wafir Widget (packages/wafir): A web component built with Lit that you can embed in any web application to collect user feedback.
- Bridge Service (apps/bridge): A Fastify-based backend service that handles feedback submissions, file uploads, and GitHub integration. See the wafir-infrastructure repo for deployment and infrastructure details.
- Test Web Page (packages/wafir/index.html): A simple HTML page to test the Wafir widget in isolation.
- Public Documentation Site (apps/www): An Astro-based website for public documentation deployed on GitHub Pages.
- Configuration Examples (examples/): Sample YAML files showing how to configure the Wafir widget.
🚀 Tech Stack
Wafir (Widget)
- Lit: Simple, fast Web Components.
- Nanostores: A tiny state manager for React, Preact, Vue, Svelte, and vanilla JS.
- Modern Screenshot: Accurate DOM-to-Canvas rendering for feedback context.
- OpenAPI Fetch: Type-safe API fetching.
Bridge (Backend/API)
- Fastify: Fast and low overhead web framework for Node.js.
- Multi-destination Feedback Routing: Route user feedback, bug reports, and suggestions to multiple projects or repositories using the new
targetskey in your configuration. Screenshots and assets are routed via targets instead of a storage key.- Octokit: Integration with GitHub for automated issue creation. - Swagger/OpenAPI: Automated API documentation.
Monorepo Tooling
📂 Project Structure
wafir/: The client-side widget built with Lit. It's designed to be embedded in any web application as a standard web component.bridge/: The backend server built with Fastify. It handles submissions, file uploads (to S3), and integrations (like GitHub).
🛠️ Installation
This project is a monorepo managed by pnpm and Turborepo.
- Clone the repository:
git clone https://github.com/BPS-Consulting/wafir.git
cd wafir- Install dependencies:
pnpm installConfiguration (Targets-based)
The Wafir widget now routes feedback with a flexible targets: config block—allowing routing to multiple destinations (projects/repos).
Migration from legacy storage config:
The legacy
storagekey configuration has been removed. All routing is now handled using thetargetsarray and form-leveltargetsreferences. To migrate, define each destination under thetargetskey, and update your forms to reference the appropriate target viatargets: [targetId].
📋 JSON Schema for IDE Support
Wafir provides a JSON Schema for configuration files to enable autocomplete, validation, and documentation in your IDE. See docs/schema/README.md for detailed setup instructions.
Quick setup for JSON files:
{
"$schema": "https://raw.githubusercontent.com/BPS-Consulting/wafir/refs/heads/main/wafir-config.schema.json",
"title": "Contact Us",
"targets": [...]
}Quick setup for YAML files:
# yaml-language-server: $schema=https://raw.githubusercontent.com/BPS-Consulting/wafir/refs/wafir-config.schema.json
title: Contact Us
targets: [...]Example (see /examples/default/wafir.yaml for full template)
title: "Contact Us"
targets:
- id: default
type: github/issues
target: your-username/your-repo
authRef: "YOUR_INSTALLATION_ID"
- id: project
type: github/project
target: your-username/your-project-id
authRef: "YOUR_INSTALLATION_ID"
forms:
- id: feedback
label: Feedback
icon: 👍
targets: [project] # Routes feedback to 'project' target
fields:
- id: rating
type: rating
attributes:
label: "How satisfied are you with our website?"
validations:
required: true
- id: description
type: textarea
attributes:
label: "What is the main reason for this rating?"
validations:
required: false
- id: issue
label: Issue
icon: 🐞
targets: [default] # Routes feedback to 'default' target
fields:
- id: title
type: input
attributes:
label: "What issue did you encounter?"
validations:
required: true
- id: description
type: textarea
attributes:
label: "Additional information:"
validations:
required: trueSee
/examplesfor reference configs using the new targets paradigm.
🏃♂️ Running Locally
To start the development environment:
pnpm devThis command runs turbo run dev, which spins up:
- The Wafir Widget in watch mode.
- The Bridge API server.
🏗️ Building
To build all packages for production:
pnpm buildTo build the browser version of the Wafir widget and copy it to the www site:
cd packages/wafir && pnpm run build:browser
cd apps/www && pnpm run build🔧 Configuration
Bridge Environment Variables
Create a .env file in the bridge/ directory based on the usage requirements. You typically need:
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY: For S3 access.GITHUB_TOKEN: For GitHub issue creation integration.
Widget Configuration
The widget can be configured via attributes or JavaScript initialization. See the wafir/ directory for specific implementation details.
CSS Customization
Wafir uses Shadow DOM for isolation but exposes CSS custom properties for theming. Set these on the wafir-widget element:
Reporter Variables
| Variable | Default | Description |
| --------------------------------- | ----------------------------- | ------------------- |
| --wafir-font-family | System fonts | Font stack |
| --wafir-font-size | 14px | Base font size |
| --wafir-text-color | #111827 | Primary text color |
| --wafir-text-secondary | #6b7280 | Muted text color |
| --wafir-primary-color | #2563eb | Brand color |
| --wafir-primary-hover | #1d4ed8 | Hover state |
| --wafir-border-color | #e5e7eb | Border color |
| --wafir-button-size | 48px | Trigger button size |
| --wafir-button-border-radius | 50% | Button shape |
| --wafir-button-offset | 20px | Edge distance |
| --wafir-button-icon-size | 24px | Icon size |
| --wafir-button-shadow | 0 4px 12px rgba(0,0,0,0.15) | Button shadow |
| --wafir-button-shadow-hover | 0 6px 16px rgba(0,0,0,0.2) | Hover shadow |
| --wafir-tooltip-bg | #1f2937 | Tooltip background |
| --wafir-backdrop-color | rgba(0,0,0,0.5) | Modal backdrop |
| --wafir-modal-bg | white | Modal background |
| --wafir-modal-border-radius | 12px | Modal corners |
| --wafir-modal-max-width | 800px | Modal width |
| --wafir-modal-padding | 20px | Modal spacing |
| --wafir-modal-shadow | 0 20px 60px rgba(0,0,0,0.3) | Modal shadow |
| --wafir-modal-title-font-size | 18px | Title size |
| --wafir-modal-title-font-weight | 600 | Title weight |
| --wafir-modal-title-color | --wafir-text-color | Title color |
Form Variables
| Variable | Default | Description |
| ------------------------------- | ------------- | ---------------- |
| --wafir-form-text-color | #374151 | Form text |
| --wafir-form-bg | transparent | Form background |
| --wafir-form-padding | 20px | Form padding |
| --wafir-form-border-color | #d1d5db | Input borders |
| --wafir-form-border-radius | 6px | Input corners |
| --wafir-form-input-padding | 10px 12px | Input spacing |
| --wafir-form-input-color | #111827 | Input text |
| --wafir-form-input-bg | #ffffff | Input background |
| --wafir-form-primary-color | #2563eb | Submit button |
| --wafir-form-primary-hover | #1d4ed8 | Submit hover |
| --wafir-form-disabled-color | #9ca3af | Disabled state |
| --wafir-form-bg-secondary | #f3f4f6 | Secondary bg |
| --wafir-form-bg-tertiary | #f9fafb | Tertiary bg |
| --wafir-form-text-secondary | #6b7280 | Secondary text |
| --wafir-form-telemetry-bg | #f9fafb | Telemetry bg |
| --wafir-form-telemetry-border | #e5e7eb | Telemetry border |
| --wafir-form-logs-bg | #111827 | Logs background |
| --wafir-form-logs-text | #f3f4f6 | Logs text |
| --wafir-form-log-warn | #fde047 | Warning color |
| --wafir-form-log-error | #f87171 | Error color |
Highlighter Variables
| Variable | Default | Description |
| ----------------------------------- | --------------------- | ------------ |
| --wafir-highlighter-overlay-bg | rgba(0,0,0,0.1) | Overlay bg |
| --wafir-highlighter-primary-color | #2563eb | Border color |
| --wafir-highlighter-highlight-bg | rgba(37,99,235,0.1) | Fill color |
Example
wafir-widget {
--wafir-primary-color: #6366f1;
--wafir-primary-hover: #818cf8;
--wafir-modal-bg: #ffffff;
--wafir-text-color: #1f2937;
--wafir-form-border-radius: 8px;
}🤝 Contributing
- Fork the repo
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Credits
- This project uses normalize.css v8.0.1 by Nicolas Gallagher, licensed under the MIT License.
Distribution & Usage
📦 Using via NPM (Module, ESM)
Install:
npm install wafirImport and use in your project:
import "wafir";
// The web component is now registered and ready to use in your HTMLThen add the widget to your HTML:
<wafir-widget
config-url="/wafir.yaml"
bridge-url="https://your-bridge.example.com"
></wafir-widget>You can also import styles if needed:
import "wafir/styles/widget.css";🌐 Using via CDN/IIFE (Browser Global)
Add to your HTML:
<script
type="module"
src="https://cdn.jsdelivr.net/npm/wafir/dist/browser/wafir.browser.js"
></script>This automatically registers the <wafir-widget> custom element. You can then use it anywhere in your HTML:
<wafir-widget
config-url="/wafir.yaml"
bridge-url="https://your-bridge.example.com"
></wafir-widget>Optionally include styles from the CDN:
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/wafir/dist/browser/styles/wafir-widget.css"
/>See full docs at GitHub Pages.
