Skip to content

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.vue has an unclear scope. [VERIFY-UI-2]: what is pModal?

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.vue etc.) need verification.
  • Buttons in custom components are sometimes <div @click> instead of <button> — see accessibility.md § VERIFY-A11Y-4.

10. Recommendations

Phase 0

  • Decompose top 5 oversized components (>2,000 lines) into smaller child components. Pick Cards/ContentCard.vue first (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.scss file with brand colours; migrate inline #ED3F56 references.
  • Choose a single icon source (npm or CDN, not both).
  • BootstrapVue → Bootstrap 5 utility-class sweep.
  • Fix Sidebar/ vs Sidebars/ and Calender/ 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-scheme usage