wad-lab 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/bin/index.js +9 -1
  2. package/package.json +1 -1
  3. package/templates/game-memory-cards/index.html +24 -0
  4. package/templates/game-memory-cards/script.js +90 -0
  5. package/templates/game-memory-cards/style.css +74 -0
  6. package/templates/game-rock-paper-scissors/index.html +35 -0
  7. package/templates/game-rock-paper-scissors/script.js +49 -0
  8. package/templates/game-rock-paper-scissors/style.css +67 -0
  9. package/templates/game-tic-tac-toe/index.html +30 -0
  10. package/templates/game-tic-tac-toe/script.js +82 -0
  11. package/templates/game-tic-tac-toe/style.css +66 -0
  12. package/templates/game-whack-a-mole/index.html +34 -0
  13. package/templates/game-whack-a-mole/script.js +83 -0
  14. package/templates/game-whack-a-mole/style.css +75 -0
  15. package/templates/html-css-js/index.html +224 -27
  16. package/templates/html-css-js/script.js +358 -25
  17. package/templates/html-css-js/style.css +452 -11
  18. package/templates/vue-cart-router-pinia/index.html +12 -0
  19. package/templates/vue-cart-router-pinia/package.json +20 -0
  20. package/templates/vue-cart-router-pinia/src/App.vue +78 -0
  21. package/templates/vue-cart-router-pinia/src/main.js +9 -0
  22. package/templates/vue-cart-router-pinia/src/router/index.js +17 -0
  23. package/templates/vue-cart-router-pinia/src/stores/cartStore.js +58 -0
  24. package/templates/vue-cart-router-pinia/src/views/CartView.vue +139 -0
  25. package/templates/vue-cart-router-pinia/src/views/CheckoutView.vue +144 -0
  26. package/templates/vue-cart-router-pinia/src/views/ProductCatalogView.vue +73 -0
  27. package/templates/vue-cart-router-pinia/vite.config.js +6 -0
  28. package/templates/vue-memory-game/index.html +12 -0
  29. package/templates/vue-memory-game/package.json +19 -0
  30. package/templates/vue-memory-game/src/App.vue +106 -0
  31. package/templates/vue-memory-game/src/main.js +7 -0
  32. package/templates/vue-memory-game/src/stores/memoryStore.js +64 -0
  33. package/templates/vue-memory-game/vite.config.js +6 -0
  34. package/templates/vue-todo-pinia/index.html +12 -0
  35. package/templates/vue-todo-pinia/package.json +19 -0
  36. package/templates/vue-todo-pinia/src/App.vue +179 -0
  37. package/templates/vue-todo-pinia/src/main.js +7 -0
  38. package/templates/vue-todo-pinia/src/stores/todoStore.js +50 -0
  39. package/templates/vue-todo-pinia/vite.config.js +6 -0
  40. package/templates/vue-todo-router/index.html +12 -0
  41. package/templates/vue-todo-router/package.json +19 -0
  42. package/templates/vue-todo-router/src/App.vue +55 -0
  43. package/templates/vue-todo-router/src/data/todoState.js +38 -0
  44. package/templates/vue-todo-router/src/main.js +7 -0
  45. package/templates/vue-todo-router/src/router/index.js +17 -0
  46. package/templates/vue-todo-router/src/views/AddTodoView.vue +85 -0
  47. package/templates/vue-todo-router/src/views/TodoDetailView.vue +89 -0
  48. package/templates/vue-todo-router/src/views/TodoListView.vue +77 -0
  49. package/templates/vue-todo-router/vite.config.js +6 -0
@@ -0,0 +1,179 @@
1
+ <script setup>
2
+ import { ref } from 'vue'
3
+ import { useTodoStore } from './stores/todoStore'
4
+
5
+ const store = useTodoStore()
6
+ const newTodoText = ref('')
7
+
8
+ function handleAdd() {
9
+ store.addTodo(newTodoText.value)
10
+ newTodoText.value = ''
11
+ }
12
+ </script>
13
+
14
+ <template>
15
+ <div class="todo-app">
16
+ <h1>Todo List (Pinia)</h1>
17
+
18
+ <form @submit.prevent="handleAdd" class="add-form">
19
+ <input
20
+ type="text"
21
+ v-model="newTodoText"
22
+ placeholder="What needs to be done?"
23
+ required
24
+ />
25
+ <button type="submit" class="btn btn-add">Add</button>
26
+ </form>
27
+
28
+ <div class="filters">
29
+ <button
30
+ type="button"
31
+ class="filter-btn"
32
+ :class="{ active: store.filter === 'all' }"
33
+ @click="store.setFilter('all')"
34
+ >
35
+ All ({{ store.totalCount }})
36
+ </button>
37
+ <button
38
+ type="button"
39
+ class="filter-btn"
40
+ :class="{ active: store.filter === 'active' }"
41
+ @click="store.setFilter('active')"
42
+ >
43
+ Pending ({{ store.pendingCount }})
44
+ </button>
45
+ <button
46
+ type="button"
47
+ class="filter-btn"
48
+ :class="{ active: store.filter === 'completed' }"
49
+ @click="store.setFilter('completed')"
50
+ >
51
+ Completed ({{ store.completedCount }})
52
+ </button>
53
+ </div>
54
+
55
+ <ul class="todo-list">
56
+ <li v-for="item in store.filteredTodos" :key="item.id" class="todo-item">
57
+ <label>
58
+ <input
59
+ type="checkbox"
60
+ :checked="item.done"
61
+ @change="store.toggleTodo(item.id)"
62
+ />
63
+ <span :class="{ completed: item.done }">{{ item.text }}</span>
64
+ </label>
65
+ <button
66
+ type="button"
67
+ class="btn-delete"
68
+ @click="store.deleteTodo(item.id)"
69
+ >
70
+ ✕
71
+ </button>
72
+ </li>
73
+ </ul>
74
+
75
+ <div v-if="store.todos.length === 0" class="empty-state">
76
+ No todos found. Add one above!
77
+ </div>
78
+
79
+ <div class="footer-actions" v-if="store.completedCount > 0">
80
+ <button type="button" class="btn btn-clear" @click="store.clearCompleted()">
81
+ Clear Completed
82
+ </button>
83
+ </div>
84
+ </div>
85
+ </template>
86
+
87
+ <style scoped>
88
+ .todo-app {
89
+ max-width: 450px;
90
+ margin: 30px auto;
91
+ font-family: Arial, sans-serif;
92
+ }
93
+
94
+ .add-form {
95
+ display: flex;
96
+ gap: 8px;
97
+ margin-bottom: 15px;
98
+ }
99
+
100
+ .add-form input {
101
+ flex: 1;
102
+ padding: 8px;
103
+ font-size: 14px;
104
+ }
105
+
106
+ .btn {
107
+ padding: 8px 16px;
108
+ cursor: pointer;
109
+ }
110
+
111
+ .btn-add {
112
+ background-color: #27ae60;
113
+ color: white;
114
+ border: none;
115
+ }
116
+
117
+ .filters {
118
+ display: flex;
119
+ gap: 8px;
120
+ margin-bottom: 15px;
121
+ }
122
+
123
+ .filter-btn {
124
+ padding: 5px 10px;
125
+ background-color: #eee;
126
+ border: 1px solid #ccc;
127
+ cursor: pointer;
128
+ }
129
+
130
+ .filter-btn.active {
131
+ background-color: #2980b9;
132
+ color: white;
133
+ border-color: #2980b9;
134
+ }
135
+
136
+ .todo-list {
137
+ list-style: none;
138
+ padding: 0;
139
+ margin: 0;
140
+ }
141
+
142
+ .todo-item {
143
+ display: flex;
144
+ justify-content: space-between;
145
+ align-items: center;
146
+ padding: 8px 0;
147
+ border-bottom: 1px solid #eee;
148
+ }
149
+
150
+ .completed {
151
+ text-decoration: line-through;
152
+ color: #888;
153
+ }
154
+
155
+ .btn-delete {
156
+ background: none;
157
+ border: none;
158
+ color: #e74c3c;
159
+ cursor: pointer;
160
+ font-size: 16px;
161
+ }
162
+
163
+ .empty-state {
164
+ text-align: center;
165
+ color: #888;
166
+ padding: 20px 0;
167
+ }
168
+
169
+ .footer-actions {
170
+ margin-top: 15px;
171
+ text-align: right;
172
+ }
173
+
174
+ .btn-clear {
175
+ background-color: #e74c3c;
176
+ color: white;
177
+ border: none;
178
+ }
179
+ </style>
@@ -0,0 +1,7 @@
1
+ import { createApp } from 'vue'
2
+ import { createPinia } from 'pinia'
3
+ import App from './App.vue'
4
+
5
+ const app = createApp(App)
6
+ app.use(createPinia())
7
+ app.mount('#app')
@@ -0,0 +1,50 @@
1
+ import { defineStore } from 'pinia'
2
+
3
+ export const useTodoStore = defineStore('todo', {
4
+ state: () => ({
5
+ todos: [
6
+ { id: 1, text: 'Study Web Application Development', done: false },
7
+ { id: 2, text: 'Complete Lab Assignment', done: true }
8
+ ],
9
+ filter: 'all'
10
+ }),
11
+ getters: {
12
+ filteredTodos: (state) => {
13
+ if (state.filter === 'active') {
14
+ return state.todos.filter((t) => !t.done)
15
+ }
16
+ if (state.filter === 'completed') {
17
+ return state.todos.filter((t) => t.done)
18
+ }
19
+ return state.todos
20
+ },
21
+ totalCount: (state) => state.todos.length,
22
+ pendingCount: (state) => state.todos.filter((t) => !t.done).length,
23
+ completedCount: (state) => state.todos.filter((t) => t.done).length
24
+ },
25
+ actions: {
26
+ addTodo(text) {
27
+ if (!text || !text.trim()) return
28
+ this.todos.push({
29
+ id: Date.now(),
30
+ text: text.trim(),
31
+ done: false
32
+ })
33
+ },
34
+ toggleTodo(id) {
35
+ const item = this.todos.find((t) => t.id === id)
36
+ if (item) {
37
+ item.done = !item.done
38
+ }
39
+ },
40
+ deleteTodo(id) {
41
+ this.todos = this.todos.filter((t) => t.id !== id)
42
+ },
43
+ setFilter(filterName) {
44
+ this.filter = filterName
45
+ },
46
+ clearCompleted() {
47
+ this.todos = this.todos.filter((t) => !t.done)
48
+ }
49
+ }
50
+ })
@@ -0,0 +1,6 @@
1
+ import { defineConfig } from 'vite'
2
+ import vue from '@vitejs/plugin-vue'
3
+
4
+ export default defineConfig({
5
+ plugins: [vue()]
6
+ })
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Vue Router Todo App</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/main.js"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "vue-todo-router",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "vue": "^3.5.44",
13
+ "vue-router": "^5.4.0"
14
+ },
15
+ "devDependencies": {
16
+ "@vitejs/plugin-vue": "^6.0.10",
17
+ "vite": "^8.3.4"
18
+ }
19
+ }
@@ -0,0 +1,55 @@
1
+ <template>
2
+ <div class="app-container">
3
+ <header class="app-header">
4
+ <h1>Vue Router Todo App</h1>
5
+ <nav class="nav">
6
+ <router-link to="/" class="nav-link">Task List</router-link>
7
+ <span class="divider">|</span>
8
+ <router-link to="/add" class="nav-link">Add New Task</router-link>
9
+ </nav>
10
+ </header>
11
+
12
+ <main class="main-content">
13
+ <router-view />
14
+ </main>
15
+ </div>
16
+ </template>
17
+
18
+ <style scoped>
19
+ .app-container {
20
+ max-width: 500px;
21
+ margin: 30px auto;
22
+ font-family: Arial, sans-serif;
23
+ }
24
+
25
+ .app-header {
26
+ border-bottom: 2px solid #333;
27
+ padding-bottom: 15px;
28
+ margin-bottom: 20px;
29
+ }
30
+
31
+ .nav {
32
+ display: flex;
33
+ gap: 10px;
34
+ align-items: center;
35
+ }
36
+
37
+ .nav-link {
38
+ text-decoration: none;
39
+ color: #2980b9;
40
+ font-weight: bold;
41
+ }
42
+
43
+ .nav-link.router-link-exact-active {
44
+ color: #27ae60;
45
+ text-decoration: underline;
46
+ }
47
+
48
+ .divider {
49
+ color: #aaa;
50
+ }
51
+
52
+ .main-content {
53
+ padding: 10px 0;
54
+ }
55
+ </style>
@@ -0,0 +1,38 @@
1
+ import { reactive } from 'vue'
2
+
3
+ export const todoState = reactive({
4
+ todos: [
5
+ { id: 1, title: 'Install Node.js & Vue CLI', description: 'Ensure the environment is ready for WAD development', done: true },
6
+ { id: 2, title: 'Build Vue Router Navigation', description: 'Implement multi-view routing and parameter handling', done: false },
7
+ { id: 3, title: 'Prepare for Lab Exam', description: 'Review state management and component communications', done: false }
8
+ ],
9
+
10
+ addTodo(title, description) {
11
+ if (!title || !title.trim()) return
12
+ const newId = this.todos.length > 0 ? Math.max(...this.todos.map((t) => t.id)) + 1 : 1
13
+ this.todos.push({
14
+ id: newId,
15
+ title: title.trim(),
16
+ description: description ? description.trim() : '',
17
+ done: false
18
+ })
19
+ },
20
+
21
+ toggleTodo(id) {
22
+ const item = this.todos.find((t) => t.id === Number(id))
23
+ if (item) {
24
+ item.done = !item.done
25
+ }
26
+ },
27
+
28
+ deleteTodo(id) {
29
+ const index = this.todos.findIndex((t) => t.id === Number(id))
30
+ if (index !== -1) {
31
+ this.todos.splice(index, 1)
32
+ }
33
+ },
34
+
35
+ getTodoById(id) {
36
+ return this.todos.find((t) => t.id === Number(id))
37
+ }
38
+ })
@@ -0,0 +1,7 @@
1
+ import { createApp } from 'vue'
2
+ import App from './App.vue'
3
+ import router from './router'
4
+
5
+ const app = createApp(App)
6
+ app.use(router)
7
+ app.mount('#app')
@@ -0,0 +1,17 @@
1
+ import { createRouter, createWebHistory } from 'vue-router'
2
+ import TodoListView from '../views/TodoListView.vue'
3
+ import AddTodoView from '../views/AddTodoView.vue'
4
+ import TodoDetailView from '../views/TodoDetailView.vue'
5
+
6
+ const routes = [
7
+ { path: '/', name: 'TodoList', component: TodoListView },
8
+ { path: '/add', name: 'AddTodo', component: AddTodoView },
9
+ { path: '/todo/:id', name: 'TodoDetail', component: TodoDetailView, props: true }
10
+ ]
11
+
12
+ const router = createRouter({
13
+ history: createWebHistory(),
14
+ routes
15
+ })
16
+
17
+ export default router
@@ -0,0 +1,85 @@
1
+ <script setup>
2
+ import { ref } from 'vue'
3
+ import { useRouter } from 'vue-router'
4
+ import { todoState } from '../data/todoState'
5
+
6
+ const router = useRouter()
7
+ const title = ref('')
8
+ const description = ref('')
9
+
10
+ function handleSubmit() {
11
+ todoState.addTodo(title.value, description.value)
12
+ router.push('/')
13
+ }
14
+ </script>
15
+
16
+ <template>
17
+ <div>
18
+ <h2>Add New Task</h2>
19
+ <form @submit.prevent="handleSubmit" class="add-form">
20
+ <div class="form-group">
21
+ <label for="title">Task Title:</label>
22
+ <input id="title" type="text" v-model="title" required placeholder="Enter task title" />
23
+ </div>
24
+
25
+ <div class="form-group">
26
+ <label for="desc">Description:</label>
27
+ <textarea id="desc" v-model="description" rows="3" placeholder="Enter optional details"></textarea>
28
+ </div>
29
+
30
+ <div class="form-actions">
31
+ <button type="submit" class="btn btn-save">Save Task</button>
32
+ <router-link to="/" class="btn btn-cancel">Cancel</router-link>
33
+ </div>
34
+ </form>
35
+ </div>
36
+ </template>
37
+
38
+ <style scoped>
39
+ .add-form {
40
+ display: flex;
41
+ flex-direction: column;
42
+ gap: 12px;
43
+ max-width: 400px;
44
+ }
45
+
46
+ .form-group {
47
+ display: flex;
48
+ flex-direction: column;
49
+ gap: 4px;
50
+ }
51
+
52
+ input, textarea {
53
+ padding: 8px;
54
+ font-size: 14px;
55
+ border: 1px solid #ccc;
56
+ border-radius: 4px;
57
+ }
58
+
59
+ .form-actions {
60
+ display: flex;
61
+ gap: 10px;
62
+ margin-top: 10px;
63
+ }
64
+
65
+ .btn {
66
+ padding: 8px 16px;
67
+ border-radius: 4px;
68
+ text-decoration: none;
69
+ font-size: 14px;
70
+ cursor: pointer;
71
+ border: none;
72
+ }
73
+
74
+ .btn-save {
75
+ background-color: #27ae60;
76
+ color: white;
77
+ }
78
+
79
+ .btn-cancel {
80
+ background-color: #95a5a6;
81
+ color: white;
82
+ display: inline-flex;
83
+ align-items: center;
84
+ }
85
+ </style>
@@ -0,0 +1,89 @@
1
+ <script setup>
2
+ import { computed } from 'vue'
3
+ import { useRoute, useRouter } from 'vue-router'
4
+ import { todoState } from '../data/todoState'
5
+
6
+ const route = useRoute()
7
+ const router = useRouter()
8
+
9
+ const todo = computed(() => {
10
+ return todoState.getTodoById(route.params.id)
11
+ })
12
+
13
+ function handleDelete() {
14
+ if (todo.value) {
15
+ todoState.deleteTodo(todo.value.id)
16
+ router.push('/')
17
+ }
18
+ }
19
+ </script>
20
+
21
+ <template>
22
+ <div v-if="todo" class="detail-card">
23
+ <h2>Task Details</h2>
24
+ <p><strong>ID:</strong> {{ todo.id }}</p>
25
+ <p><strong>Title:</strong> {{ todo.title }}</p>
26
+ <p><strong>Description:</strong> {{ todo.description || 'No description provided' }}</p>
27
+ <p><strong>Status:</strong> {{ todo.done ? 'Completed ✅' : 'Pending ⏳' }}</p>
28
+
29
+ <div class="actions">
30
+ <button type="button" class="btn btn-toggle" @click="todoState.toggleTodo(todo.id)">
31
+ Mark as {{ todo.done ? 'Pending' : 'Completed' }}
32
+ </button>
33
+ <button type="button" class="btn btn-delete" @click="handleDelete">Delete</button>
34
+ <router-link to="/" class="btn btn-back">Back to List</router-link>
35
+ </div>
36
+ </div>
37
+ <div v-else class="not-found">
38
+ <p>Task not found.</p>
39
+ <router-link to="/">Return to List</router-link>
40
+ </div>
41
+ </template>
42
+
43
+ <style scoped>
44
+ .detail-card {
45
+ max-width: 450px;
46
+ border: 1px solid #ddd;
47
+ border-radius: 6px;
48
+ padding: 20px;
49
+ background-color: #fafafa;
50
+ }
51
+
52
+ .actions {
53
+ display: flex;
54
+ gap: 10px;
55
+ margin-top: 20px;
56
+ flex-wrap: wrap;
57
+ }
58
+
59
+ .btn {
60
+ padding: 8px 14px;
61
+ border: none;
62
+ border-radius: 4px;
63
+ cursor: pointer;
64
+ text-decoration: none;
65
+ font-size: 14px;
66
+ }
67
+
68
+ .btn-toggle {
69
+ background-color: #2980b9;
70
+ color: white;
71
+ }
72
+
73
+ .btn-delete {
74
+ background-color: #e74c3c;
75
+ color: white;
76
+ }
77
+
78
+ .btn-back {
79
+ background-color: #7f8c8d;
80
+ color: white;
81
+ display: inline-flex;
82
+ align-items: center;
83
+ }
84
+
85
+ .not-found {
86
+ padding: 20px;
87
+ text-align: center;
88
+ }
89
+ </style>
@@ -0,0 +1,77 @@
1
+ <script setup>
2
+ import { todoState } from '../data/todoState'
3
+ </script>
4
+
5
+ <template>
6
+ <div>
7
+ <h2>Task List</h2>
8
+ <ul class="task-list">
9
+ <li v-for="item in todoState.todos" :key="item.id" class="task-item">
10
+ <label>
11
+ <input
12
+ type="checkbox"
13
+ :checked="item.done"
14
+ @change="todoState.toggleTodo(item.id)"
15
+ />
16
+ <span :class="{ completed: item.done }">{{ item.title }}</span>
17
+ </label>
18
+ <div class="actions">
19
+ <router-link :to="'/todo/' + item.id" class="btn-link">View Details</router-link>
20
+ <button type="button" class="btn-del" @click="todoState.deleteTodo(item.id)">Delete</button>
21
+ </div>
22
+ </li>
23
+ </ul>
24
+
25
+ <div v-if="todoState.todos.length === 0" class="empty">
26
+ No tasks available. Click "Add Task" to create one.
27
+ </div>
28
+ </div>
29
+ </template>
30
+
31
+ <style scoped>
32
+ .task-list {
33
+ list-style: none;
34
+ padding: 0;
35
+ margin: 15px 0;
36
+ }
37
+
38
+ .task-item {
39
+ display: flex;
40
+ justify-content: space-between;
41
+ align-items: center;
42
+ padding: 10px 0;
43
+ border-bottom: 1px solid #ddd;
44
+ }
45
+
46
+ .completed {
47
+ text-decoration: line-through;
48
+ color: #888;
49
+ }
50
+
51
+ .actions {
52
+ display: flex;
53
+ gap: 10px;
54
+ align-items: center;
55
+ }
56
+
57
+ .btn-link {
58
+ color: #2980b9;
59
+ text-decoration: none;
60
+ font-size: 13px;
61
+ }
62
+
63
+ .btn-del {
64
+ background-color: #e74c3c;
65
+ color: white;
66
+ border: none;
67
+ padding: 4px 8px;
68
+ border-radius: 3px;
69
+ cursor: pointer;
70
+ }
71
+
72
+ .empty {
73
+ text-align: center;
74
+ color: #888;
75
+ padding: 20px 0;
76
+ }
77
+ </style>
@@ -0,0 +1,6 @@
1
+ import { defineConfig } from 'vite'
2
+ import vue from '@vitejs/plugin-vue'
3
+
4
+ export default defineConfig({
5
+ plugins: [vue()]
6
+ })