Skip to content

UI Component Library

Design system

Bootstrap-Vue 2 (^2.23.1) — Vue 2 wrapper around Bootstrap 4 classes. Plus Bootstrap 5 loaded via CDN script.

  • Bootstrap-Vue: provides <b-navbar>, <b-table>, <b-form>, <b-modal>, <b-button>, … with Vue-friendly props
  • Bootstrap 5 CDN: https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js — loaded in nuxt.config.js head

The two Bootstraps coexist. Bootstrap-Vue's components produce Bootstrap-4-style HTML; the Bootstrap 5 JS overrides some behaviour. This is a smell — the visual result depends on which one wins at render time.

Recommendation: pick one. Either upgrade Bootstrap-Vue to v3 (which targets Bootstrap 5) or drop the Bootstrap 5 CDN.

CSS

  • assets/css/blueprint.css — from BlueprintJS (because Polotno uses it; the designer FE bundles it too)
  • assets/css/bootstrap.css — local copy of Bootstrap
  • assets/css/common.css — project-specific styles

All loaded globally in nuxt.config.js. No CSS Modules, no scoped CSS at the page level (verify per-page <style scoped> adoption).

Components

Only 4 in components/:

  • Navbar.vue — the global navbar with role-typed item visibility (large file — most of the conditional UI lives here)
  • Notification.vue — notification display
  • skeletonCard.vue — loading skeleton placeholder
  • ToasterProgress.vue — toast with progress bar

The rest of the UI is inline in pages. Each pages/*.vue is largely self-contained. This is consistent with the "small staff tool, evolved organically" history but is a maintainability liability: a UI change to a table or form must be made in N pages.

Forms

No form library (no Vuelidate, no VeeValidate). Forms are hand-rolled per-page:

<b-form @submit.prevent="onSubmit">
  <b-form-input v-model="email" required />
  <b-form-input v-model="password" type="password" required />
  <b-button type="submit">Login</b-button>
</b-form>

Validation is per-field via HTML5 attributes (required, type="email") plus ad-hoc JS in onSubmit. Error messages are inconsistent across pages.

File upload

filepond + plugins (@nuxtjs/filepond is the wrapper; vue-filepond for Vue integration). Used in pages with image/file uploads.

Notifications

Two libraries:

  • vue-notification — used in layouts/default.vue (<notifications group="app" /> and <notifications group="auth" />)
  • vue-toastification — declared in package.json but adoption unclear (verify which pages use it)

Pick one.

Icons

No icon library declared in deps. Icons probably come from Bootstrap-Vue's icon set (<b-icon>) or from custom SVG embedded in components.

Theming

No dark mode. No theming.

Color picker

vue-color (^2.8.1) — used somewhere for color selection (probably in template editor pages or PostColorCorrection).

Carousels / sliders

No carousel library beyond what Bootstrap provides. Polotno has its own carousel handling for carousel templates.

QR

qrcode (^1.5.3) — used for QR generation in templates (verify; possibly in Polotno's QrSection.js).

Masonry

masonry-layout (^4.2.2) — masonry grid layout for image library / template displays.

Time

moment (^2.30.1) + moment-timezone (^0.5.45). In maintenance mode; if rewriting consider date-fns or luxon.

Recommendations

ID Recommendation Effort
U-1 Decide Bootstrap-Vue v2 + BS4 vs BV3 + BS5; eliminate the dual-Bootstrap setup Medium
U-2 Extract repeated UI patterns (tables, forms, modals) into components/ Medium (per-pattern)
U-3 Pick one toast lib (sonner vs vue-notification) Small
U-4 Add a form-validation library (Vuelidate is the standard Vue 2 choice) Medium
U-5 Document the icon strategy; pin a library Small
U-6 Plan a UI library migration when this app moves off Vue 2 (likely to Vue 3 / Nuxt 3 — Vue 2 reached EOL Dec 2023) Large