Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/atrium-telegram/app/assets/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
--ui-secondary: var(--tg-theme-link-color);
--ui-border: var(--tg-theme-section-separator-color);
--ui-text: var(--tg-theme-text-color);
--ui-text-muted: var(--tg-theme-hint-color);
--ui-bg: var(--tg-theme-section-bg-color);

--ui-color-neutral-400: var(--tg-theme-subtitle-text-color);
Expand Down
10 changes: 2 additions & 8 deletions apps/atrium-telegram/app/components/Button.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
<template>
<button
class="p-3 tg-bg-button w-full rounded-2xl font-medium cursor-pointer active:scale-95 duration-200"
@click="handleClick"
@click="vibrate"
>
<slot />
</button>
</template>

<script setup lang="ts">
import { hapticFeedback } from '@telegram-apps/sdk-vue'

function handleClick() {
if (hapticFeedback.impactOccurred.isAvailable()) {
hapticFeedback.impactOccurred('light')
}
}
const { vibrate } = useFeedback()
</script>
8 changes: 7 additions & 1 deletion apps/atrium-telegram/app/components/CreateCard.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
<template>
<div class="flex flex-col gap-4 justify-center items-center h-full min-h-40 border-2 border-default border-dashed rounded-lg">
<div class="flex flex-col gap-4 justify-center items-center h-full min-h-40 border border-default border-dashed rounded-lg">

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Emit click from the component and vibrate on the root to ensure consistent haptics across the whole card

Right now, clicking the card background opens the modal (parent @click) but doesn’t vibrate; only the inner button vibrates. Centralize the behavior in CreateCard: vibrate and emit a click from the root, and remove the button-level handler.

Apply within these ranges:

-  <div class="flex flex-col gap-4 justify-center items-center h-full min-h-40 border border-default border-dashed rounded-lg">
+  <div class="flex flex-col gap-4 justify-center items-center h-full min-h-40 border border-default border-dashed rounded-lg" @click="onClick">
       :label="label"
-      :ui="{
-        label: 'font-medium',
-      }"
-      @click="vibrate"
+      :ui="buttonUi"

Add outside the selected ranges in <script setup>:

const emit = defineEmits<{ (e: 'click', ev?: MouseEvent): void }>()
const buttonUi = { label: 'font-medium' }

function onClick(ev?: MouseEvent) {
  vibrate()
  emit('click', ev)
}

Also applies to: 10-14

<UIcon :name="icon" class="size-10 text-muted/50" />

<UButton
size="md"
variant="solid"
color="secondary"
:label="label"
:ui="{
label: 'font-medium',
}"
@click="vibrate"
/>
</div>
</template>

<script setup lang="ts">
defineProps<{ label: string, icon: string }>()

const { vibrate } = useFeedback()
</script>
8 changes: 2 additions & 6 deletions apps/atrium-telegram/app/components/Navigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@
</template>

<script setup lang="ts">
import { hapticFeedback } from '@telegram-apps/sdk-vue'

const { t } = useI18n()
const { vibrate } = useFeedback()
const router = useRouter()

const mainRoutes = computed(() => [
Expand Down Expand Up @@ -64,10 +63,7 @@ const mainRoutes = computed(() => [
])

function handleClick(path: string) {
if (hapticFeedback.impactOccurred.isAvailable()) {
hapticFeedback.impactOccurred('light')
}

vibrate()
router.push(path)
}
</script>
38 changes: 15 additions & 23 deletions apps/atrium-telegram/app/components/TaskCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,16 @@
</template>
</UPopover>
</template>
<UTooltip v-else-if="canComplete" text="Задача выполнена?">
<UCheckbox
v-model="checkbox"
color="secondary"
variant="list"
size="xl"
icon="i-lucide-check"
class="mt-1.5 duration-200 motion-preset-bounce"
@change="onStartCompleting"
/>
</UTooltip>
<UCheckbox
v-else-if="canComplete"
v-model="checkbox"
color="secondary"
variant="list"
size="xl"
icon="i-lucide-check"
class="mt-1.5 duration-200 motion-preset-bounce"
@change="onStartCompleting"
/>
<UCheckbox
v-else
v-model="checkbox"
Expand Down Expand Up @@ -65,8 +64,9 @@
}"
class="group/task duration-200 motion-preset-bounce cursor-pointer"
:class="[
isFocused && 'border border-secondary',
isFocused && 'border border-secondary/25',
]"
@click="vibrate"
>
<div class="flex flex-col gap-2 items-start">
<div class="flex flex-col gap-1 items-start text-left">
Expand Down Expand Up @@ -116,7 +116,7 @@ const { task } = defineProps<{
}>()

const { t } = useI18n()
const toast = useToast()
const { vibrate } = useFeedback()
const actionToast = useActionToast()
const taskStore = useTaskStore()
const userStore = useUserStore()
Expand All @@ -140,7 +140,6 @@ const canFocus = computed(() => task.performerId === userStore.id && !isComplete
const isFocused = computed(() => task.id === performer.value?.focusedTaskId)

const checkbox = ref(false)
const toastId = ref(`task-close-${task.id}`)

const items = computed<DropdownMenuItem[]>(() => {
const menuItems: DropdownMenuItem[] = [
Expand Down Expand Up @@ -195,21 +194,14 @@ async function onUnfocus() {
}

function onStartCompleting() {
vibrate()

if (!checkbox.value) {
return
}

modalCompleteTask.open({ taskId: task.id })

checkbox.value = false

toast.add({
id: toastId.value,
title: 'Закрываем задачу?',
description: 'Сразу как успешную или есть что добавить? Заполните форму.',
color: 'secondary',
type: 'foreground',
duration: 5000,
})
}
</script>
43 changes: 25 additions & 18 deletions apps/atrium-telegram/app/components/TaskList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,25 +54,21 @@
</div>

<div v-if="canEdit" class="flex flex-row gap-2">
<UTooltip :text="`Редактировать проект «${list?.name}»`">
<UButton
variant="outline"
color="neutral"
size="md"
icon="i-lucide-pencil"
@click="modalUpdateTaskList.open({ listId })"
/>
</UTooltip>
<UButton
variant="outline"
color="neutral"
size="md"
icon="i-lucide-pencil"
@click="handleEditTaskList"
/>

<UTooltip :text="`${$t('app.create.task.button')} в проекте «${list?.name}»`">
<UButton
variant="solid"
color="secondary"
size="md"
icon="i-lucide-plus"
@click="modalCreateTask.open({ performerId: userStore.id, listId })"
/>
</UTooltip>
<UButton
variant="solid"
color="secondary"
size="md"
icon="i-lucide-plus"
@click="handleCreateTask"
/>
</div>
Comment on lines 56 to 72

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Icon-only buttons need accessible labels

Since tooltips were removed, add aria-label (and optionally title) so screen readers and hover users know the action.

 <UButton
   variant="outline"
   color="neutral"
   size="md"
   icon="i-lucide-pencil"
+  aria-label="Редактировать список"
+  title="Редактировать список"
   @click="handleEditTaskList"
 />
 
 <UButton
   variant="solid"
   color="secondary"
   size="md"
   icon="i-lucide-plus"
+  aria-label="Создать задачу"
+  title="Создать задачу"
   @click="handleCreateTask"
 />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div v-if="canEdit" class="flex flex-row gap-2">
<UTooltip :text="`Редактировать проект «${list?.name`">
<UButton
variant="outline"
color="neutral"
size="md"
icon="i-lucide-pencil"
@click="modalUpdateTaskList.open({ listId })"
/>
</UTooltip>
<UButton
variant="outline"
color="neutral"
size="md"
icon="i-lucide-pencil"
@click="handleEditTaskList"
/>
<UTooltip :text="`${$t('app.create.task.button')} в проекте «${list?.name`">
<UButton
variant="solid"
color="secondary"
size="md"
icon="i-lucide-plus"
@click="modalCreateTask.open({ performerId: userStore.id, listId })"
/>
</UTooltip>
<UButton
variant="solid"
color="secondary"
size="md"
icon="i-lucide-plus"
@click="handleCreateTask"
/>
</div>
<div v-if="canEdit" class="flex flex-row gap-2">
<UButton
variant="outline"
color="neutral"
size="md"
icon="i-lucide-pencil"
aria-label="Редактировать список"
title="Редактировать список"
@click="handleEditTaskList"
/>
<UButton
variant="solid"
color="secondary"
size="md"
icon="i-lucide-plus"
aria-label="Создать задачу"
title="Создать задачу"
@click="handleCreateTask"
/>
</div>
🤖 Prompt for AI Agents
In apps/atrium-telegram/app/components/TaskList.vue around lines 56 to 72, the
icon-only UButton components lack accessible labels; add an aria-label for each
icon-only button (e.g., aria-label="Edit task list" on the pencil button and
aria-label="Create task" on the plus button) and optionally add a matching title
attribute for hover tooltips so screen readers and sighted users can understand
the action.

</div>

Expand Down Expand Up @@ -103,6 +99,7 @@ const { listId, currentUserId } = defineProps<{
currentUserId: string
}>()

const { vibrate } = useFeedback()
const userStore = useUserStore()
const taskStore = useTaskStore()

Expand All @@ -129,4 +126,14 @@ const canEdit = computed(() => list.value?.chat?.members.some((member) => member
const overlay = useOverlay()
const modalCreateTask = overlay.create(ModalCreateTask)
const modalUpdateTaskList = overlay.create(ModalUpdateTaskList)

function handleEditTaskList() {
vibrate()
modalUpdateTaskList.open({ listId })
}

function handleCreateTask() {
vibrate()
modalCreateTask.open({ performerId: userStore.id, listId })
}
</script>
2 changes: 2 additions & 0 deletions apps/atrium-telegram/app/components/TasksTodaySwitch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
root: 'flex-row-reverse items-center',
label: 'mr-3 text-base/5 md:text-lg/5 font-semibold',
}"
@change="vibrate"
/>
</template>

<script setup lang="ts">
const { vibrate } = useFeedback()
const taskStore = useTaskStore()
</script>
15 changes: 15 additions & 0 deletions apps/atrium-telegram/app/composables/useFeedback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { hapticFeedback } from '@telegram-apps/sdk-vue'

function _useFeedback() {
function vibrate() {
if (hapticFeedback.impactOccurred.isAvailable()) {
hapticFeedback.impactOccurred('light')
}
}

return {
vibrate,
}
}

export const useFeedback = createSharedComposable(_useFeedback)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Missing import: createSharedComposable will be undefined

This will throw at runtime. Import it from @vueuse/core.

+import { createSharedComposable } from '@vueuse/core'
 import { hapticFeedback } from '@telegram-apps/sdk-vue'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const useFeedback = createSharedComposable(_useFeedback)
import { createSharedComposable } from '@vueuse/core'
import { hapticFeedback } from '@telegram-apps/sdk-vue'
export const useFeedback = createSharedComposable(_useFeedback)
🤖 Prompt for AI Agents
In apps/atrium-telegram/app/composables/useFeedback.ts around line 15,
createSharedComposable is used but not imported which will cause a runtime
error; add the import statement "import { createSharedComposable } from
'@vueuse/core'" at the top of the file (with other imports) so
createSharedComposable is defined before exporting useFeedback.

21 changes: 13 additions & 8 deletions apps/atrium-telegram/app/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@
<PageContainer :back="false">
<div class="flex flex-col md:flex-row gap-6 md:gap-2 md:items-center md:justify-between">
<div class="flex flex-row gap-3.5 items-center">
<UTooltip :text="$t('app.update.user-photo.button')">
<UAvatar
:src="userStore?.avatarUrl ?? undefined"
class="size-14 cursor-pointer hover:scale-95 active:scale-90 duration-200"
@click="modalUploadUserAvatar.open()"
/>
</UTooltip>
<UAvatar
:src="userStore?.avatarUrl ?? undefined"
class="size-14 cursor-pointer hover:scale-95 active:scale-90 duration-200"
@click="handleUploadUserAvatar"
/>

<div class="flex flex-col gap-1">
<h2 class="text-xl/6 md:text-2xl lg:text-3xl font-bold tracking-tight">
Expand Down Expand Up @@ -42,7 +40,7 @@
</div>
</div>

<div class="mb-32 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-4">
<div class="mb-20 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-4">
<TaskList
v-for="taskList in myLists"
:key="taskList.id"
Expand All @@ -63,6 +61,8 @@
import { ModalCreateTaskList, ModalUploadUserAvatar } from '#components'
import { getLocalTimeZone, isToday, parseDate } from '@internationalized/date'

const { vibrate } = useFeedback()

const overlay = useOverlay()
const modalCreateTaskList = overlay.create(ModalCreateTaskList)
const modalUploadUserAvatar = overlay.create(ModalUploadUserAvatar)
Expand All @@ -77,6 +77,11 @@ const myLists = computed(() =>
)
const myTodayTasks = computed(() => myLists.value.flatMap((taskList) => taskList.tasks.filter((task) => !task.completedAt && task.date && isToday(parseDate(task.date), getLocalTimeZone()))))

function handleUploadUserAvatar() {
vibrate()
modalUploadUserAvatar.open()
}

useHead({
title: 'Суши Атриум',
})
Expand Down
14 changes: 14 additions & 0 deletions apps/atrium-telegram/i18n/locales/ru-RU.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
"app": {
"home": "Пространство",
"create": {
"task": {
"button": "Создать задачу",
"title": "Создание задачи"
},
"task-list": {
"button": "Создать проект",
"title": "Создание проекта"
Expand All @@ -16,6 +20,16 @@
"user-photo": {
"button": "Обновить фото",
"title": "Обновление фото пользователя"
},
"task": {
"button": "Обновить задачу",
"title": "Обновление задачи",
"completion": "Закрытие задачи",
"close": "Закрыть задачу"
},
"task-list": {
"button": "Обновить проект",
"title": "Обновление проекта"
}
}
}
Expand Down