wad-lab 1.0.5 → 1.0.7

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 (47) 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/vue-cart-router-pinia/index.html +12 -0
  16. package/templates/vue-cart-router-pinia/package.json +20 -0
  17. package/templates/vue-cart-router-pinia/src/App.vue +78 -0
  18. package/templates/vue-cart-router-pinia/src/main.js +9 -0
  19. package/templates/vue-cart-router-pinia/src/router/index.js +17 -0
  20. package/templates/vue-cart-router-pinia/src/stores/cartStore.js +58 -0
  21. package/templates/vue-cart-router-pinia/src/views/CartView.vue +139 -0
  22. package/templates/vue-cart-router-pinia/src/views/CheckoutView.vue +144 -0
  23. package/templates/vue-cart-router-pinia/src/views/ProductCatalogView.vue +73 -0
  24. package/templates/vue-cart-router-pinia/vite.config.js +6 -0
  25. package/templates/vue-memory-game/index.html +12 -0
  26. package/templates/vue-memory-game/package.json +19 -0
  27. package/templates/vue-memory-game/src/App.vue +106 -0
  28. package/templates/vue-memory-game/src/main.js +7 -0
  29. package/templates/vue-memory-game/src/stores/memoryStore.js +64 -0
  30. package/templates/vue-memory-game/vite.config.js +6 -0
  31. package/templates/vue-todo-pinia/index.html +12 -0
  32. package/templates/vue-todo-pinia/package.json +19 -0
  33. package/templates/vue-todo-pinia/src/App.vue +179 -0
  34. package/templates/vue-todo-pinia/src/main.js +7 -0
  35. package/templates/vue-todo-pinia/src/stores/todoStore.js +50 -0
  36. package/templates/vue-todo-pinia/vite.config.js +6 -0
  37. package/templates/vue-todo-router/index.html +12 -0
  38. package/templates/vue-todo-router/package.json +19 -0
  39. package/templates/vue-todo-router/src/App.vue +55 -0
  40. package/templates/vue-todo-router/src/data/todoState.js +38 -0
  41. package/templates/vue-todo-router/src/main.js +7 -0
  42. package/templates/vue-todo-router/src/router/index.js +17 -0
  43. package/templates/vue-todo-router/src/views/AddTodoView.vue +85 -0
  44. package/templates/vue-todo-router/src/views/TodoDetailView.vue +89 -0
  45. package/templates/vue-todo-router/src/views/TodoListView.vue +77 -0
  46. package/templates/vue-todo-router/vite.config.js +6 -0
  47. package/templates/servlet-flow/SERVLET_EXAM_CHEATSHEET.md +0 -389
@@ -0,0 +1,106 @@
1
+ <script setup>
2
+ import { onMounted } from 'vue'
3
+ import { useMemoryStore } from './stores/memoryStore'
4
+
5
+ const store = useMemoryStore()
6
+
7
+ onMounted(() => {
8
+ store.initGame()
9
+ })
10
+ </script>
11
+
12
+ <template>
13
+ <div class="game-wrapper">
14
+ <h1>Vue Pinia Memory Game</h1>
15
+
16
+ <div class="stats">
17
+ <span>Moves: {{ store.moves }}</span>
18
+ <span>Matches: {{ store.matches }} / {{ store.symbols.length }}</span>
19
+ </div>
20
+
21
+ <button type="button" class="btn" @click="store.initGame()">Restart Game</button>
22
+
23
+ <div v-if="store.isGameOver" class="win-banner">
24
+ 🎉 You won in {{ store.moves }} moves!
25
+ </div>
26
+
27
+ <div class="grid">
28
+ <div
29
+ v-for="card in store.cards"
30
+ :key="card.id"
31
+ class="card"
32
+ :class="{ flipped: card.isFlipped, matched: card.isMatched }"
33
+ @click="store.flipCard(card)"
34
+ >
35
+ {{ card.isFlipped || card.isMatched ? card.symbol : '?' }}
36
+ </div>
37
+ </div>
38
+ </div>
39
+ </template>
40
+
41
+ <style scoped>
42
+ .game-wrapper {
43
+ max-width: 360px;
44
+ margin: 30px auto;
45
+ text-align: center;
46
+ font-family: Arial, sans-serif;
47
+ }
48
+
49
+ .stats {
50
+ display: flex;
51
+ justify-content: space-around;
52
+ font-size: 18px;
53
+ font-weight: bold;
54
+ margin: 15px 0;
55
+ }
56
+
57
+ .btn {
58
+ padding: 8px 16px;
59
+ background-color: #2980b9;
60
+ color: white;
61
+ border: none;
62
+ border-radius: 4px;
63
+ cursor: pointer;
64
+ margin-bottom: 20px;
65
+ }
66
+
67
+ .win-banner {
68
+ padding: 10px;
69
+ background-color: #d4edda;
70
+ color: #155724;
71
+ margin-bottom: 15px;
72
+ border-radius: 4px;
73
+ font-weight: bold;
74
+ }
75
+
76
+ .grid {
77
+ display: grid;
78
+ grid-template-columns: repeat(4, 75px);
79
+ gap: 10px;
80
+ justify-content: center;
81
+ }
82
+
83
+ .card {
84
+ width: 75px;
85
+ height: 75px;
86
+ background-color: #34495e;
87
+ color: white;
88
+ font-size: 32px;
89
+ display: flex;
90
+ justify-content: center;
91
+ align-items: center;
92
+ border-radius: 6px;
93
+ cursor: pointer;
94
+ user-select: none;
95
+ }
96
+
97
+ .card.flipped {
98
+ background-color: #ecf0f1;
99
+ color: #2c3e50;
100
+ }
101
+
102
+ .card.matched {
103
+ background-color: #2ecc71;
104
+ color: white;
105
+ }
106
+ </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,64 @@
1
+ import { defineStore } from 'pinia'
2
+
3
+ export const useMemoryStore = defineStore('memory', {
4
+ state: () => ({
5
+ symbols: ['🐶', '🐱', '🐭', '🐹', '🐰', '🦊'],
6
+ cards: [],
7
+ flippedCards: [],
8
+ moves: 0,
9
+ matches: 0,
10
+ isLocked: false
11
+ }),
12
+ getters: {
13
+ isGameOver: (state) => state.matches === state.symbols.length
14
+ },
15
+ actions: {
16
+ initGame() {
17
+ const duplicated = [...this.symbols, ...this.symbols]
18
+ duplicated.sort(() => 0.5 - Math.random())
19
+
20
+ this.cards = duplicated.map((symbol, idx) => ({
21
+ id: idx,
22
+ symbol: symbol,
23
+ isFlipped: false,
24
+ isMatched: false
25
+ }))
26
+
27
+ this.flippedCards = []
28
+ this.moves = 0
29
+ this.matches = 0
30
+ this.isLocked = false
31
+ },
32
+
33
+ flipCard(card) {
34
+ if (this.isLocked || card.isFlipped || card.isMatched) return
35
+
36
+ card.isFlipped = true
37
+ this.flippedCards.push(card)
38
+
39
+ if (this.flippedCards.length === 2) {
40
+ this.moves++
41
+ this.checkMatch()
42
+ }
43
+ },
44
+
45
+ checkMatch() {
46
+ const [card1, card2] = this.flippedCards
47
+
48
+ if (card1.symbol === card2.symbol) {
49
+ card1.isMatched = true
50
+ card2.isMatched = true
51
+ this.matches++
52
+ this.flippedCards = []
53
+ } else {
54
+ this.isLocked = true
55
+ setTimeout(() => {
56
+ card1.isFlipped = false
57
+ card2.isFlipped = false
58
+ this.flippedCards = []
59
+ this.isLocked = false
60
+ }, 800)
61
+ }
62
+ }
63
+ }
64
+ })
@@ -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 Pinia Todo List</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-pinia",
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
+ "pinia": "^4.1.0",
13
+ "vue": "^3.5.44"
14
+ },
15
+ "devDependencies": {
16
+ "@vitejs/plugin-vue": "^6.0.10",
17
+ "vite": "^8.3.4"
18
+ }
19
+ }
@@ -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