UI Component Library¶
Status: Audit v0.1 (2026-05-09).
1. Design system¶
| Property | Value | Source |
|---|---|---|
| Design system | No documented design system; an unbranded mix of Bootstrap 5 + bootstrap-vue + custom components | package.json:36-37, nuxt.config.js:121-167 |
| Storybook / similar | No | Not in deps |
| Visual regression testing | No (no Chromatic/Percy/Loki) | Same |
| Component documentation | No | No docs site |
The component library is an organic accretion rather than a curated design system. There is no published list of "official" primitives, no design tokens file, no theming layer. Custom components in components/ co-exist with bootstrap-vue components (<b-table>, <b-modal>, <b-form-input>, etc.) and direct HTML.
Finding [WC-UI-1] (Severity: Medium): No design system. Adding a new feature requires reading existing components to figure out what conventions to copy. Visual inconsistency is high (different button styles, different modal frames, different spacing rhythms — see "pattern consistency" §5).
2. CSS approach¶
| Approach | In use? | Source |
|---|---|---|
| Tailwind | No | Not in deps |
| CSS Modules | No | Vue 2 SFC <style> blocks instead |
| styled-components / emotion | No | Vue codebase |
SCSS via <style lang="scss"> |
Yes | package.json:80-81 (sass, sass-loader); @nuxtjs/style-resources injects shared variables |
| Vanilla CSS | Yes, assets/css/style.css, assets/css/appstyle.css |
nuxt.config.js:172 |
| Scoped styles | Mostly | <style scoped> is the convention |
| Bootstrap CSS | Yes, multiple versions (CDN 5.0.2, 5.2.0-beta1; npm 5.2.0) | nuxt.config.js:135-167 |
| FontAwesome CSS | Yes (CDN + npm) | nuxt.config.js:140, package.json:17 |
Finding [WC-UI-2] (Severity: Medium): Three Bootstrap versions are loaded simultaneously. CSS specificity wars are baked in. (Cross-ref performance.md § Finding WC-PERF-5.)
3. Component inventory¶
3.1 Counts¶
| Property | Value | Source |
|---|---|---|
| Total component files | 161 | find components -type f \| wc -l |
| Top-level components | ~88 | find components -maxdepth 1 -type f \| wc -l |
| Subdirectories | (see below) | ls components/ |
3.2 Component subdirectory structure¶
components/
├── BookCallDropdown.vue Sales/booking CTA
├── Buttons/ Reusable button variants
├── Calender/ FullCalendar wrapper (note: spelling)
├── Cards/ Card-shaped components
├── Charts/ LineChart, PieChart, ChartLegendItem
├── Chatbot.vue AI chatbot widget (2,512 lines)
├── ColorSelect/ Color pickers
├── ContentIdeas/ Topic / content suggestion UIs
├── ContextMenu.vue Right-click context menu
├── Dashboard/ Dashboard sub-components (charts, gauges, hashtag, leaderboard, reach, roi, socialcard)
├── ExplorerContent.vue Generic content explorer
├── Forms/ Form primitives (EaInputSwitch, etc.)
├── ImageManager.vue Image management UI (2,311 lines)
├── Layout/ Page sections (EaTopbar, EaMainSection)
├── MyContent.vue, MyArticles*, etc. Content listings
├── modals (~30 *Modal.vue files) Modal dialogs
├── paywall.vue Paywall / blocker
├── SettingSocialAccounts/ Social-account settings sub-tree
├── SettingsBilling.vue, SettingsBrandKit.vue, SettingsSchedule.vue Settings pages (in components, not pages — confusing)
├── Sidebar/, Sidebars/ Sidebar variants (note: two folders, easy to mistype)
└── VueNetworkIdentify.vue Network identification widget
Finding [WC-UI-3] (Severity: Low–Medium): Sidebar/ and Sidebars/ (singular vs plural) coexist. Easy to import the wrong one. Same for Calender/ (misspelled — should be Calendar/); breaking the typo is a wide refactor.
3.3 Reusable primitives¶
The Buttons/, Cards/, Charts/, ColorSelect/, Forms/, Layout/ subdirectories suggest an intent of a primitive layer. [VERIFY-UI-1] how many components actually re-use these primitives vs. inline the equivalent markup?
Finding [WC-UI-4] (Severity: Medium): The "primitives" folders contain a small number of components (e.g., Buttons/ has only a few items based on directory size — verify), and many top-level components inline their own buttons/cards rather than using the primitives. Re-grouping toward consistent primitive use is a Phase 1 effort.
3.4 Largest components¶
(Cross-ref architecture-overview.md § 3.1.) The biggest components by LOC:
| Lines | File | Likely scope |
|---|---|---|
| 3,678 | components/editPostModal.vue |
Editing a single post (modal) |
| 3,328 | components/Cards/ContentCard.vue |
A card representing a post |
| 2,512 | components/Chatbot.vue |
AI chatbot |
| 2,311 | components/ImageManager.vue |
Image management |
| 2,200 | components/createContentModal.vue |
Multi-step content creation modal |
| 1,841 | components/paywall.vue |
Paywall (ironic — should be small) |
| 1,795 | components/MyContent.vue |
Content listing |
| 1,756 | components/Layout/EaTopbar.vue |
Topbar |
| 1,724 | components/SettingSocialAccounts/index.vue |
Social-accounts settings tab |
| 1,664 | components/SettingsBilling.vue |
Billing settings tab |
These are all "monolith components." A typical SPA's modal is 200–600 lines; a ContentCard is 50–200 lines. Numbers an order of magnitude larger indicate features that could be decomposed.
Finding [WC-UI-5] (Severity: High): 7 components exceed 1,500 lines. Decomposing into child components is the most effective leverage on maintainability of the UI layer. Phase 1 effort.
4. Modal patterns¶
There are 30+ modal components (ls components/*Modal.vue \| wc -l ≈ 30). The existing project doc ../18-modal-patterns.md inventories them and identifies patterns.
Key audit-relevant points:
- All modals use bootstrap-vue's
<b-modal>. - Naming inconsistency: PascalCase (
AddWebsiteModal.vue), camelCase (createContentModal.vue), single-word (pModal.vue). - 3+ generic confirmation modals exist (
DeleteModal.vue,ArchiveModal.vue,pModal.vue) — opportunity to consolidate. pModal.vuehas an unclear scope. [VERIFY-UI-2]: what ispModal?
5. Pattern consistency — forms¶
5.1 Form-handling library¶
There is no dedicated Vue form library (no VeeValidate, FormKit, Vuelidate observed in deps).
grep -rEn "VeeValidate\|formkit\|vuelidate" pages components plugins package.json → empty.
Forms are managed with data() state + methods for submit + bootstrap-vue's per-input validation hooks (<b-form-input :state="...">). Validation is per-component, ad hoc.
5.2 Field validation¶
grep -rEn "validate(\)\|validateForm\(\)" pages components returns many sites — each component implements its own validation function. No shared validators.
Finding [WC-UI-6] (Severity: Medium): Form validation is ad hoc per component. Shared validators (email, phone, password strength via zxcvbn, etc.) are reimplemented across the codebase. Phase 1 — adopt a single form-handling library, e.g., VeeValidate 3 (Vue 2 compatible) or migrate during Vue 3 to FormKit.
5.3 Password strength¶
zxcvbn is in deps (package.json:105) along with vue-password-strength-meter (package.json:96). These should be used at signup and password-change forms. [VERIFY-UI-3]: confirm the password-meter is used everywhere a password is set.
6. Theming¶
There is no observed theme system (no theme/ folder, no prefers-color-scheme handling in CSS).
grep -rEn "prefers-color-scheme" assets pages components 2>/dev/null \| head → [VERIFY-UI-4] likely empty.
Brand colours appear inline in <style> blocks (#ED3F56 is a recurring red, #FF6B4A a warm orange — visible in Chatbot.vue inline styles). No central palette file in assets/scss/_variables.scss would need to be confirmed.
Finding [WC-UI-7] (Severity: Low): No dark mode. Brand customisation per account would require theme infrastructure not currently in place. May be out of scope; flag here for product.
7. Iconography¶
| Source | In use? |
|---|---|
| FontAwesome 6 (CDN + npm) | Yes, ubiquitous |
| BlueprintJS Icons | Used inside Polotno editor |
@meronex/icons |
Polotno editor only (polotno-editor/package.json) |
Custom SVGs in assets/img/ |
Some |
The dual icon-source (FA from CDN + npm) is wasteful. (Cross-ref performance.md § WC-PERF-12.)
8. BootstrapVue + Bootstrap interaction¶
The repo registers bootstrap-vue with { css: false } (nuxt.config.js:249), then loads Bootstrap 5 CSS from CDN. bootstrap-vue is built for Bootstrap 4 markup; some classes have changed in BS5 (mr-* → me-*, etc.). Many components still use Bootstrap 4 utility classes.
Finding [WC-UI-8] (Severity: Medium): bootstrap-vue (Bootstrap 4 conventions) + Bootstrap 5 CSS = subtle visual bugs. The component library is internally inconsistent. A Phase 1 effort: replace mr-*/ml-*/pl-*/pr-* with their BS5 equivalents (me-*/ms-*/ps-*/pe-*); this is a mechanical sweep.
9. Accessibility of components¶
(Cross-ref accessibility.md.)
<b-modal>traps focus by default — good.- Custom modals (
pModal.vueetc.) need verification. - Buttons in custom components are sometimes
<div @click>instead of<button>— seeaccessibility.md§ VERIFY-A11Y-4.
10. Recommendations¶
Phase 0¶
- Decompose top 5 oversized components (>2,000 lines) into smaller child components. Pick
Cards/ContentCard.vuefirst (3,328 lines, used many times). - Adopt a single primary modal style; deprecate alternates over time.
Phase 1¶
- Adopt VeeValidate 3 (Vue 2 compatible) or similar for forms.
- Add a
theme.scssfile with brand colours; migrate inline#ED3F56references. - Choose a single icon source (npm or CDN, not both).
- BootstrapVue → Bootstrap 5 utility-class sweep.
- Fix
Sidebar/vsSidebars/andCalender/typo.
Phase 2¶
- Vue 3 migration brings the opportunity to switch to a modern Vue UI library (Vuetify 3, PrimeVue, Naive UI, etc.) and retire bootstrap-vue.
11. Open questions¶
Tracked in ./verify-markers.md:
- [VERIFY-UI-1] Primitive-folder usage rate
- [VERIFY-UI-2] Scope of
pModal.vue - [VERIFY-UI-3] Password-strength meter coverage
- [VERIFY-UI-4]
prefers-color-schemeusage