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 innuxt.config.jshead
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 Bootstrapassets/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 displayskeletonCard.vue— loading skeleton placeholderToasterProgress.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 inlayouts/default.vue(<notifications group="app" />and<notifications group="auth" />)vue-toastification— declared inpackage.jsonbut 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 |