skills/landing_page-vue2-editor/SKILL.md
Vue 2 Options API patterns for the Landing Page editor — Vuex namespaced stores, Ant Design Vue components, mixins, computed getters/setters, and axios API calls.
npx skillsauth add vuluu2k/skills landing_page-vue2-editorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Vue 2.6 + Vuex 3 + Ant Design Vue 1.6 — Page builder editor application.
| Topic | Description | Reference | |-------|-------------|-----------| | Component Pattern | Options API, computed getters/setters, mapState/mapGetters | core-components | | Vuex Store | Namespaced modules, mutations, actions, Vuex architecture | core-vuex | | API & Mixins | Axios calls, mixin patterns, custom plugins | core-api-mixins |
<template>
<div class="my-trait">
<a-input
v-model="title"
:placeholder="$t('ui.placeholder.title')"
@change="onTitleChange"
/>
<a-select v-model="status" style="width: 100%">
<a-select-option :value="1">{{ $t('ui.active') }}</a-select-option>
<a-select-option :value="0">{{ $t('ui.inactive') }}</a-select-option>
</a-select>
<a-checkbox v-model="autoPlay">Auto Play</a-checkbox>
<a-button type="primary" @click="save">
{{ $t('ui.save') }}
</a-button>
</div>
</template>
<script>
import { mapState, mapGetters, mapActions } from 'vuex'
import axios from 'axios'
export default {
name: 'MyTrait',
props: {
elementId: { type: String, required: true }
},
data() {
return {
loading: false,
localData: null
}
},
computed: {
...mapState('page', ['data', 'sync']),
...mapState('ui', ['selectedElements']),
...mapGetters('page', ['currentPage']),
// Two-way computed — đọc từ store, ghi lại store
title: {
get() {
return this.$store.state.page.data.name
},
set(value) {
this.$store.commit('page/set-name', value)
}
},
status: {
get() {
return this.$store.state.page.data.status
},
set(value) {
this.$store.commit('page/set-status', value)
}
}
},
methods: {
...mapActions('page', ['refresh-async-products']),
onTitleChange() {
// Debounce hoặc xử lý thêm
},
async save() {
this.loading = true
try {
const res = await axios.put(`/api/pages/${this.data.id}`, {
name: this.title,
status: this.status
}, {
headers: { 'x-org-id': this.$store.state.organization.id }
})
if (res.status === 200) {
this.$notification.success({ message: 'Saved!' })
}
} catch (e) {
this.$notification.error({ message: 'Save failed' })
} finally {
this.loading = false
}
}
},
mounted() {
this['refresh-async-products']()
}
}
</script>
<style scoped lang="sass">
.my-trait
padding: 12px
.ant-input
margin-bottom: 8px
</style>
development
Vue 3 Composition API — <script setup>, reactivity (shallowRef/ref), props without destructure, computed, watch, provide/inject, and composables. Use when the project uses modern Vue 3 Composition API style.
development
Vue 3 Options API — data, props, computed, methods, watch, emits, provide/inject, lifecycle hooks, and mixins. Use when the project uses Options API style (Vue 2 legacy or explicit Vue 3 Options API preference).
tools
Best practices for mixing Ant Design Vue components with Tailwind CSS utility classes. Use this skill to keep styling consistent without custom CSS files.
development
Pinia state management for Vue 3 using Composition API (Setup Stores) — TypeScript-first, storeToRefs for reactivity, focused stores, and API calls in composables. Use when the project uses Vue 3 Composition API / <script setup>.