diff --git a/web/vue-app/src/assets/actions-shared.css b/web/vue-app/src/assets/actions-shared.css
new file mode 100644
index 0000000..56fea14
--- /dev/null
+++ b/web/vue-app/src/assets/actions-shared.css
@@ -0,0 +1,36 @@
+.actions {
+ display: flex;
+ gap: 3rem;
+ justify-content: center;
+ margin-top: 0.5rem;
+}
+.actions button {
+ padding: 1rem 2.2rem;
+ border-radius: 12px;
+ border: 0;
+ cursor: pointer;
+ font-weight: 700;
+ font-size: 1.25rem;
+ transition: background 0.18s;
+ min-width: 120px;
+}
+
+/* Unified error style */
+.error {
+ color: #e53e3e;
+ margin-top: 0.7rem;
+ text-align: center;
+ background: rgba(255, 107, 107, 0.1);
+ border-radius: 8px;
+ padding: 1rem;
+}
+
+@media (max-width: 480px) {
+ .actions {
+ gap: 1.2rem;
+ }
+ .actions button {
+ padding: 0.8rem 1.2rem;
+ font-size: 1.05rem;
+ min-width: 90px;
+ }
diff --git a/web/vue-app/src/assets/button-shared.css b/web/vue-app/src/assets/button-shared.css
new file mode 100644
index 0000000..7b520bd
--- /dev/null
+++ b/web/vue-app/src/assets/button-shared.css
@@ -0,0 +1,54 @@
+/* Base button style */
+.btn {
+ font-weight: 600;
+ border: none;
+ border-radius: 8px;
+ padding: 0.7rem 1.5rem;
+ font-size: 1.1rem;
+ cursor: pointer;
+ box-shadow: 0 2px 8px rgba(102, 126, 234, 0.08);
+ transition:
+ background 0.18s,
+ color 0.18s;
+ display: inline-block;
+}
+
+/* Primary button (e.g., Save, Confirm) */
+.btn-primary {
+ background: #667eea;
+ color: #fff;
+}
+.btn-primary:hover,
+.btn-primary:focus {
+ background: #5a67d8;
+}
+
+/* Secondary button (e.g., Cancel) */
+.btn-secondary {
+ background: #f3f3f3;
+ color: #666;
+}
+.btn-secondary:hover,
+.btn-secondary:focus {
+ background: #e2e8f0;
+}
+
+/* Danger button (e.g., Delete) */
+.btn-danger {
+ background: #ef4444;
+ color: #fff;
+}
+.btn-danger:hover,
+.btn-danger:focus {
+ background: #dc2626;
+}
+
+/* Green button (e.g., Confirm) */
+.btn-green {
+ background: #22c55e;
+ color: #fff;
+}
+.btn-green:hover,
+.btn-green:focus {
+ background: #16a34a;
+}
diff --git a/web/vue-app/src/assets/edit-forms.css b/web/vue-app/src/assets/edit-forms.css
new file mode 100644
index 0000000..d3afa0d
--- /dev/null
+++ b/web/vue-app/src/assets/edit-forms.css
@@ -0,0 +1,75 @@
+.edit-view,
+.child-edit-view,
+.reward-edit-view,
+.task-edit-view {
+ max-width: 400px;
+ margin: 2rem auto;
+ background: #fff;
+ border-radius: 12px;
+ box-shadow: 0 4px 24px #667eea22;
+ padding: 2rem 2.2rem 1.5rem 2.2rem;
+}
+
+.edit-view h2,
+.child-edit-view h2,
+.reward-edit-view h2,
+.task-edit-view h2 {
+ text-align: center;
+ margin-bottom: 1.5rem;
+ color: #667eea;
+}
+
+.form-group,
+.reward-form label,
+.task-form label {
+ display: block;
+ margin-bottom: 1.1rem;
+ font-weight: 500;
+ color: #444;
+ width: 100%;
+}
+
+input[type='text'],
+input[type='number'],
+.reward-form input[type='text'],
+.reward-form input[type='number'],
+.task-form input[type='text'],
+.task-form input[type='number'] {
+ display: block;
+ width: 100%;
+ margin-top: 0.4rem;
+ padding: 0.5rem;
+ border-radius: 7px;
+ border: 1px solid #cbd5e1;
+ font-size: 1rem;
+ background: #f8fafc;
+ box-sizing: border-box;
+}
+
+.btn.cancel,
+button[type='button'] {
+ background: #f3f3f3;
+ color: #666;
+}
+.btn.save,
+button[type='submit'] {
+ background: #667eea;
+ color: #fff;
+ border: none;
+ border-radius: 8px;
+ padding: 0.6rem 1.4rem;
+ font-weight: 600;
+ font-size: 1rem;
+ cursor: pointer;
+ transition: background 0.18s;
+}
+.btn.save:hover,
+button[type='submit']:hover:not(:disabled) {
+ background: #5a67d8;
+}
+
+.loading-message {
+ text-align: center;
+ color: #666;
+ margin-bottom: 1.2rem;
+}
diff --git a/web/vue-app/src/assets/layout-shared.css b/web/vue-app/src/assets/layout-shared.css
new file mode 100644
index 0000000..dfa8d06
--- /dev/null
+++ b/web/vue-app/src/assets/layout-shared.css
@@ -0,0 +1,108 @@
+/* Root layout */
+.layout-root {
+ width: 100%;
+ min-height: 100vh;
+ height: 100vh;
+ display: flex;
+ flex-direction: column;
+ padding: 0;
+ background: var(--header-bg, linear-gradient(135deg, #667eea 0%, #764ba2 100%));
+}
+
+/* Top bar */
+.topbar {
+ display: flex;
+ align-items: stretch;
+ padding: 5px 5px;
+ height: 48px;
+ width: 100%;
+ box-sizing: border-box;
+}
+
+/* Back button container and login button container */
+.back-btn-container,
+.login-btn-container {
+ height: 100%;
+ display: flex;
+ align-items: center;
+ flex: 1 1 0;
+}
+
+.back-btn-container {
+ justify-content: flex-start;
+}
+
+.login-btn-container {
+ justify-content: flex-end;
+}
+
+/* Spacer for layouts without a center nav */
+.spacer {
+ flex: 1 1 auto;
+}
+
+/* Back button */
+.back-btn {
+ background: var(--button-bg, #fff);
+ border: 0;
+ padding: 0.6rem 1rem;
+ border-radius: 8px 8px 0 0;
+ cursor: pointer;
+ color: var(--button-text, #667eea);
+ font-weight: 600;
+ height: 100%;
+ box-sizing: border-box;
+ display: flex;
+ align-items: center;
+}
+
+/* Login button inside login-btn container */
+.login-btn {
+ background: var(--button-bg, #fff);
+ border: 0;
+ padding: 0.6rem 1rem;
+ border-radius: 8px 8px 0 0;
+ cursor: pointer;
+ color: var(--button-text, #667eea);
+ font-weight: 600;
+ height: 100%;
+ display: flex;
+ align-items: center;
+}
+
+/* Main content area */
+.main-content {
+ flex: 1 1 auto;
+ width: 100%;
+ justify-content: center;
+ align-items: flex-start;
+ box-sizing: border-box;
+ min-height: 0;
+ height: 0;
+ overflow: hidden;
+ overflow-y: visible;
+}
+
+/* App version display */
+.app-version {
+ position: fixed;
+ right: 18px;
+ bottom: 12px;
+ font-size: 0.92rem;
+ color: var(--app-version, #cbd5e1);
+ opacity: 0.85;
+ z-index: 100;
+ pointer-events: none;
+ user-select: none;
+ font-family: monospace;
+}
+
+/* Responsive adjustments */
+@media (max-width: 480px) {
+ .back-btn,
+ .login-btn button {
+ padding: 0.45rem 0.75rem;
+ font-size: 0.6rem;
+ height: 100%;
+ }
+}
diff --git a/web/vue-app/src/assets/list-shared.css b/web/vue-app/src/assets/list-shared.css
new file mode 100644
index 0000000..981893a
--- /dev/null
+++ b/web/vue-app/src/assets/list-shared.css
@@ -0,0 +1,120 @@
+/* List container */
+.listbox {
+ flex: 1 1 auto;
+ max-width: 480px;
+ width: 100%;
+ max-height: calc(100vh - 4.5rem);
+ overflow-y: auto;
+ margin: 0.2rem 0 0 0;
+ display: flex;
+ flex-direction: column;
+ gap: 0.7rem;
+ background: #fff5;
+ padding: 0.2rem 0.2rem 0.2rem;
+ border-radius: 12px;
+}
+
+/* List item */
+.list-item {
+ display: flex;
+ align-items: center;
+ border: 2px outset #38c172;
+ border-radius: 8px;
+ padding: 0.2rem 1rem;
+ background: #f8fafc;
+ font-size: 1.05rem;
+ font-weight: 500;
+ transition: border 0.18s;
+ margin-bottom: 0.2rem;
+ margin-left: 0.2rem;
+ margin-right: 0.2rem;
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
+ box-sizing: border-box;
+}
+.list-item.bad {
+ border-color: #e53e3e;
+ background: #fff5f5;
+}
+.list-item.good {
+ border-color: #38c172;
+ background: #f0fff4;
+}
+
+/* Image styles */
+.list-image {
+ width: 36px;
+ height: 36px;
+ object-fit: cover;
+ border-radius: 8px;
+ margin-right: 0.7rem;
+ background: #eee;
+ flex-shrink: 0;
+}
+
+/* Name/label styles */
+.list-name {
+ flex: 1;
+ text-align: left;
+ font-weight: 600;
+}
+
+/* Points/cost/requested text */
+.list-value {
+ min-width: 60px;
+ text-align: right;
+ font-weight: 600;
+}
+
+/* Delete button */
+.delete-btn {
+ background: transparent;
+ border: none;
+ border-radius: 50%;
+ padding: 0.15rem;
+ margin-left: 0.7rem;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ transition:
+ background 0.15s,
+ box-shadow 0.15s;
+ width: 2rem;
+ height: 2rem;
+ opacity: 0.92;
+}
+.delete-btn:hover {
+ background: #ffeaea;
+ box-shadow: 0 0 0 2px #ef444422;
+ opacity: 1;
+}
+.delete-btn svg {
+ display: block;
+}
+
+/* Checkbox */
+.list-checkbox {
+ margin-left: 1rem;
+ width: 1.2em;
+ height: 1.2em;
+ accent-color: #667eea;
+ cursor: pointer;
+}
+
+/* Loading, error, empty states */
+.loading,
+.empty {
+ margin: 1.2rem 0;
+ color: #888;
+ font-size: 1.15rem;
+ font-weight: 600;
+ text-align: center;
+ line-height: 1.5;
+}
+
+/* Separator (if needed) */
+.list-separator {
+ height: 0px;
+ background: #0000;
+ margin: 0rem 0.2rem;
+ border-radius: 0px;
+}
diff --git a/web/vue-app/src/assets/view-shared.css b/web/vue-app/src/assets/view-shared.css
new file mode 100644
index 0000000..11c5f92
--- /dev/null
+++ b/web/vue-app/src/assets/view-shared.css
@@ -0,0 +1,112 @@
+.layout {
+ display: flex;
+ justify-content: center;
+ align-items: flex-start;
+}
+
+.main {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 1.5rem;
+ width: 100%;
+}
+
+.loading {
+ color: white;
+ min-height: 200px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+}
+
+/* Modal Backdrop and Modal */
+.modal-backdrop {
+ position: fixed;
+ inset: 0;
+ background: rgba(0, 0, 0, 0.4);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1200;
+}
+.modal {
+ background: #fff;
+ color: #222;
+ padding: 1.5rem 2rem;
+ border-radius: 12px;
+ min-width: 240px;
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2);
+ text-align: center;
+}
+
+/* Dialog Message */
+.dialog-message {
+ font-size: 1.08rem;
+ color: #444;
+ font-weight: 500;
+ margin-bottom: 1.2rem;
+ text-align: center;
+}
+.dialog-message .child-name {
+ color: #667eea;
+ font-weight: 700;
+ margin-left: 2px;
+}
+
+/* Info Sections (Reward/Task) */
+.info,
+.reward-info,
+.task-info {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ margin-bottom: 1rem;
+}
+.image,
+.reward-image,
+.task-image {
+ width: 72px;
+ height: 72px;
+ object-fit: cover;
+ border-radius: 8px;
+ background: #eee;
+}
+.details,
+.reward-details,
+.task-details {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+}
+.name,
+.reward-name,
+.task-name {
+ font-weight: 600;
+ font-size: 1.1rem;
+}
+.points,
+.reward-points,
+.task-points {
+ color: #667eea;
+ font-weight: 500;
+ font-size: 1rem;
+}
+
+/* Responsive Adjustments */
+@media (max-width: 900px) {
+ .layout {
+ flex-direction: column;
+ align-items: stretch;
+ }
+}
+@media (max-width: 480px) {
+ .main {
+ gap: 1rem;
+ }
+ .modal {
+ padding: 1rem;
+ min-width: 0;
+ }
+}
diff --git a/web/vue-app/src/components/AssignTaskButton.vue b/web/vue-app/src/components/AssignTaskButton.vue
deleted file mode 100644
index a3755fb..0000000
--- a/web/vue-app/src/components/AssignTaskButton.vue
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
-
-
diff --git a/web/vue-app/src/components/ChildrenListView.vue b/web/vue-app/src/components/ChildrenListView.vue
index b7ff86a..46766bd 100644
--- a/web/vue-app/src/components/ChildrenListView.vue
+++ b/web/vue-app/src/components/ChildrenListView.vue
@@ -355,7 +355,7 @@ onBeforeUnmount(() => {
Are you sure you want to permanently delete this child?
-
@@ -402,7 +402,6 @@ h1 {
}
.loading,
-.error,
.empty {
display: flex;
align-items: center;
@@ -413,13 +412,6 @@ h1 {
text-align: center;
}
-.error {
- color: #ff6b6b;
- background: rgba(255, 107, 107, 0.1);
- border-radius: 8px;
- padding: 1rem;
-}
-
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
@@ -462,6 +454,7 @@ h1 {
color: #666;
border-radius: 6px;
box-sizing: border-box;
+ font-size: 1.5rem;
}
/* consistent focus ring without changing layout */
@@ -473,27 +466,46 @@ h1 {
/* Menu overlays the card and does NOT alter flow */
.kebab-menu {
position: absolute;
- top: 44px; /* place below the button */
- right: 0; /* align to kebab button's right edge */
+ top: 44px;
+ right: 0;
margin: 0;
min-width: 150px;
- background: white;
- border-radius: 8px;
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
+ background: #f7fafcc7; /* subtle light gray for contrast */
+ border-radius: 10px;
+ border: 1.5px solid #bcc1c9; /* subtle border for definition */
+ box-shadow:
+ 0 8px 24px rgba(0, 0, 0, 0.18),
+ 0 1.5px 6px rgba(102, 126, 234, 0.08); /* stronger shadow for separation */
display: flex;
flex-direction: column;
overflow: hidden;
z-index: 30;
+ backdrop-filter: blur(11px); /* optional: adds a modern blur effect */
}
.menu-item {
- padding: 0.6rem 0.9rem;
+ padding: 1.1rem 0.9rem; /* Increase vertical padding for bigger touch area */
background: transparent;
border: 0;
text-align: left;
cursor: pointer;
font-weight: 600;
color: #333;
+ font-size: 1.1rem; /* Slightly larger text for readability */
+}
+
+.menu-item + .menu-item {
+ margin-top: 0.5rem; /* Add space between menu items */
+}
+
+@media (max-width: 600px) {
+ .menu-item {
+ padding: 0.85rem 0.7rem;
+ font-size: 1rem;
+ }
+ .menu-item + .menu-item {
+ margin-top: 0.35rem;
+ }
}
.menu-item:hover {
@@ -564,31 +576,6 @@ h1 {
font-size: 1.05rem;
}
-.actions {
- display: flex;
- gap: 0.5rem;
- justify-content: center;
- margin-top: 1rem;
-}
-
-.btn {
- padding: 0.5rem 0.8rem;
- border-radius: 8px;
- border: 0;
- cursor: pointer;
- font-weight: 700;
-}
-
-.btn.cancel {
- background: #f3f3f3;
- color: #666;
-}
-
-.btn.delete {
- background: #ff4d4f;
- color: white;
-}
-
.points {
font-size: 1.05rem;
color: #444;
diff --git a/web/vue-app/src/components/ImagePicker.vue b/web/vue-app/src/components/ImagePicker.vue
index 4f5b86f..10833d0 100644
--- a/web/vue-app/src/components/ImagePicker.vue
+++ b/web/vue-app/src/components/ImagePicker.vue
@@ -226,6 +226,7 @@ async function resizeImageFile(
ref="fileInput"
type="file"
accept=".png,.jpg,.jpeg,.gif,image/png,image/jpeg,image/gif"
+ capture="environment"
style="display: none"
@change="onFileChange"
/>
@@ -253,15 +254,15 @@ async function resizeImageFile(
- Take Photo
- Cancel
+ Take Photo
+ Cancel
- Use Photo
- Retake
+ Use Photo
+ Retake
@@ -285,8 +286,8 @@ async function resizeImageFile(
align-items: center;
}
.selectable-image {
- width: 54px;
- height: 54px;
+ width: 64px;
+ height: 64px;
object-fit: cover;
border-radius: 8px;
border: 2px solid #e6e6e6;
@@ -310,29 +311,31 @@ async function resizeImageFile(
.image-actions {
display: flex;
- gap: 1rem;
+ gap: 4rem;
justify-content: center;
- margin-top: 0.5rem;
+ margin-top: 1.2rem; /* Increased space below images */
}
.icon-btn {
background: #f3f3f3;
border: none;
border-radius: 50%;
- width: 38px;
- height: 38px;
+ width: 56px; /* Increased size */
+ height: 56px; /* Increased size */
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: background 0.18s;
- font-size: 1.5rem;
+ font-size: 2.2rem; /* Bigger + icon */
color: #667eea;
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.07);
}
-.icon-btn:hover {
- background: #e0e7ff;
+.icon-btn svg {
+ width: 32px; /* Bigger camera icon */
+ height: 32px;
}
+
.icon {
display: flex;
align-items: center;
diff --git a/web/vue-app/src/components/LoginButton.vue b/web/vue-app/src/components/LoginButton.vue
index 6becc66..0174b7a 100644
--- a/web/vue-app/src/components/LoginButton.vue
+++ b/web/vue-app/src/components/LoginButton.vue
@@ -56,8 +56,12 @@ onUnmounted(() => {
- Yes
- No
+ Yes
+ No
@@ -397,15 +398,6 @@ onUnmounted(() => {
diff --git a/web/vue-app/src/components/child/ParentView.vue b/web/vue-app/src/components/child/ParentView.vue
index 44e89d6..6e81ec9 100644
--- a/web/vue-app/src/components/child/ParentView.vue
+++ b/web/vue-app/src/components/child/ParentView.vue
@@ -6,6 +6,7 @@ import ChildDetailCard from './ChildDetailCard.vue'
import ChildTaskList from '../task/ChildTaskList.vue'
import ChildRewardList from '../reward/ChildRewardList.vue'
import { eventBus } from '@/common/eventBus'
+import '@/assets/view-shared.css'
import type {
Task,
Child,
@@ -332,7 +333,7 @@ const childId = computed(() => child.value?.id ?? null)
-
+
Loading...
Error: {{ error }}
@@ -367,13 +368,11 @@ const childId = computed(() => child.value?.id ?? null)
- Assign Tasks
-
+ Assign Tasks
+
Assign Bad Habits
-
- Assign Rewards
-
+ Assign Rewards
@@ -385,8 +384,8 @@ const childId = computed(() => child.value?.id ?? null)
Would you like to cancel the pending reward?
- Yes, Cancel Reward
- No
+ Yes
+ No
@@ -403,7 +402,7 @@ const childId = computed(() => child.value?.id ?? null)
{{ selectedTask.name }}
- {{ selectedTask.points }} pts
+ {{ selectedTask.points }} points
@@ -413,7 +412,7 @@ const childId = computed(() => child.value?.id ?? null)
{{ child?.name }}
- Yes
+ Yes
{
@@ -421,6 +420,7 @@ const childId = computed(() => child.value?.id ?? null)
selectedTask = null
}
"
+ class="btn btn-secondary"
>
Cancel
@@ -443,7 +443,7 @@ const childId = computed(() => child.value?.id ?? null)
{{
selectedReward.points_needed === 0
? 'Reward Ready!'
- : selectedReward.points_needed + ' pts needed'
+ : selectedReward.points_needed + ' more points'
}}
@@ -453,7 +453,7 @@ const childId = computed(() => child.value?.id ?? null)
>?
-
Yes
+
Yes
{
@@ -461,6 +461,7 @@ const childId = computed(() => child.value?.id ?? null)
selectedReward = null
}
"
+ class="btn btn-secondary"
>
Cancel
@@ -471,174 +472,6 @@ const childId = computed(() => child.value?.id ?? null)
diff --git a/web/vue-app/src/components/reward/RewardList.vue b/web/vue-app/src/components/reward/RewardList.vue
index e81b4a2..242ea27 100644
--- a/web/vue-app/src/components/reward/RewardList.vue
+++ b/web/vue-app/src/components/reward/RewardList.vue
@@ -2,6 +2,7 @@
import { ref, watch, onMounted, computed } from 'vue'
import { getCachedImageUrl } from '../../common/imageCache'
import type { Reward } from '@/common/models'
+import '@/assets/list-shared.css'
const props = defineProps<{
childId?: string | number
@@ -132,27 +133,27 @@ const listHeight = computed(() => {
-
+
Loading rewards...
{{ error }}
No rewards found.
-
-
![Reward]()
-
{{ reward.name }}
-
{{ reward.cost }} pts
+
+
![Reward]()
+
{{ reward.name }}
+
{{ reward.cost }} pts
{
-
+
-
+
diff --git a/web/vue-app/src/components/reward/RewardView.vue b/web/vue-app/src/components/reward/RewardView.vue
index a28dfdd..062f29d 100644
--- a/web/vue-app/src/components/reward/RewardView.vue
+++ b/web/vue-app/src/components/reward/RewardView.vue
@@ -29,8 +29,8 @@
Are you sure you want to delete this reward?
- Yes, Delete
- Cancel
+ Delete
+ Cancel
@@ -106,17 +106,20 @@ const createReward = () => {
text-align: center;
}
.actions {
- margin-top: 1.2rem;
display: flex;
- gap: 1rem;
+ gap: 3rem; /* Increased gap for more space between buttons */
justify-content: center;
+ margin-top: 0.5rem;
}
.actions button {
- padding: 0.5rem 1.2rem;
- border-radius: 8px;
- border: none;
- font-weight: 600;
+ padding: 1rem 2.2rem; /* Bigger touch area */
+ border-radius: 12px;
+ border: 0;
cursor: pointer;
+ font-weight: 700;
+ font-size: 1.25rem; /* Larger text */
+ transition: background 0.18s;
+ min-width: 120px; /* Ensures buttons are wide enough */
}
.actions button:first-child {
background: #ef4444;
diff --git a/web/vue-app/src/components/task/ChildTaskList.vue b/web/vue-app/src/components/task/ChildTaskList.vue
index b330b04..27c17c2 100644
--- a/web/vue-app/src/components/task/ChildTaskList.vue
+++ b/web/vue-app/src/components/task/ChildTaskList.vue
@@ -160,7 +160,7 @@ onBeforeUnmount(() => {
class="task-points"
:class="{ 'good-points': task.is_good, 'bad-points': !task.is_good }"
>
- {{ task.is_good ? task.points : -task.points }} pts
+ {{ task.is_good ? task.points : -task.points }} Points
@@ -233,10 +233,6 @@ onBeforeUnmount(() => {
padding: 0.5rem 0;
}
-/* Fallback for browsers that don't support flex gap */
-.task-card + .task-card {
- margin-left: 0.75rem;
-}
.task-card {
background: rgba(255, 255, 255, 0.15);
border-radius: 8px;
@@ -301,8 +297,13 @@ onBeforeUnmount(() => {
}
.task-points {
- font-size: 0.75rem;
- font-weight: 700;
+ font-size: 1rem;
+ font-weight: 900;
+ text-shadow:
+ -1px -1px 0 #1a3d1f,
+ 1px -1px 0 #1a3d1f,
+ -1px 1px 0 #1a3d1f,
+ 1px 1px 0 #1a3d1f;
}
.task-points.good-points {
diff --git a/web/vue-app/src/components/task/TaskEditView.vue b/web/vue-app/src/components/task/TaskEditView.vue
index 2c1d977..b0ea13f 100644
--- a/web/vue-app/src/components/task/TaskEditView.vue
+++ b/web/vue-app/src/components/task/TaskEditView.vue
@@ -2,6 +2,7 @@
import { ref, onMounted, computed, defineEmits, nextTick } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import ImagePicker from '@/components/ImagePicker.vue'
+import '@/assets/edit-forms.css'
const route = useRoute()
const router = useRouter()
@@ -175,8 +176,10 @@ function onAddImage({ id, file }: { id: string; file: File }) {
{{ error }}
- Cancel
-
+
+ Cancel
+
+
{{ isEdit ? 'Save' : 'Create' }}
@@ -185,77 +188,6 @@ function onAddImage({ id, file }: { id: string; file: File }) {
diff --git a/web/vue-app/src/components/task/TaskList.vue b/web/vue-app/src/components/task/TaskList.vue
index a5a45f6..b315ff0 100644
--- a/web/vue-app/src/components/task/TaskList.vue
+++ b/web/vue-app/src/components/task/TaskList.vue
@@ -2,6 +2,7 @@
import { ref, watch, onMounted, computed } from 'vue'
import { getCachedImageUrl } from '../../common/imageCache'
import type { Task } from '@/common/models'
+import '@/assets/list-shared.css'
const props = defineProps<{
childId?: string | number
@@ -143,37 +144,37 @@ const filteredTasks = computed(() => {
-
+
Loading tasks...
{{ error }}
No tasks found.
-
![Task]()
-
{{ task.name }}
-
+
+ {{ task.name }}
+
{{ task.is_good ? task.points : '-' + task.points }} pts
-
+
-
+
diff --git a/web/vue-app/src/components/task/TaskView.vue b/web/vue-app/src/components/task/TaskView.vue
index c9bf564..90ee959 100644
--- a/web/vue-app/src/components/task/TaskView.vue
+++ b/web/vue-app/src/components/task/TaskView.vue
@@ -28,8 +28,8 @@
Are you sure you want to delete this task?
- Yes, Delete
- Cancel
+ Delete
+ Cancel
@@ -108,17 +108,20 @@ const createTask = () => {
text-align: center;
}
.actions {
- margin-top: 1.2rem;
display: flex;
- gap: 1rem;
+ gap: 3rem; /* Increased gap for more space between buttons */
justify-content: center;
+ margin-top: 0.5rem;
}
.actions button {
- padding: 0.5rem 1.2rem;
- border-radius: 8px;
- border: none;
- font-weight: 600;
+ padding: 1rem 2.2rem; /* Bigger touch area */
+ border-radius: 12px;
+ border: 0;
cursor: pointer;
+ font-weight: 700;
+ font-size: 1.25rem; /* Larger text */
+ transition: background 0.18s;
+ min-width: 120px; /* Ensures buttons are wide enough */
}
.actions button:first-child {
background: #ef4444;
diff --git a/web/vue-app/src/layout/ChildLayout.vue b/web/vue-app/src/layout/ChildLayout.vue
index ec801ec..752600a 100644
--- a/web/vue-app/src/layout/ChildLayout.vue
+++ b/web/vue-app/src/layout/ChildLayout.vue
@@ -5,7 +5,7 @@
← Back
-
+
@@ -35,28 +35,9 @@ const showBack = computed(() => route.path !== '/child')
-
-
diff --git a/web/vue-app/src/layout/ParentLayout.vue b/web/vue-app/src/layout/ParentLayout.vue
index 2019a0a..894321e 100644
--- a/web/vue-app/src/layout/ParentLayout.vue
+++ b/web/vue-app/src/layout/ParentLayout.vue
@@ -150,7 +150,7 @@ onMounted(async () => {
-
+
@@ -162,35 +162,8 @@ onMounted(async () => {