diff --git a/frontend/src/assets/styles/relay.css b/frontend/src/assets/styles/relay.css
index 495ebff..7ddc9a7 100644
--- a/frontend/src/assets/styles/relay.css
+++ b/frontend/src/assets/styles/relay.css
@@ -677,3 +677,17 @@ body {
opacity: 0.6;
cursor: default;
}
+
+/* ============================================================
+ * 빈/상태 메시지 박스 (목록 로딩·빈 상태 공통)
+ * ============================================================ */
+.empty-state {
+ background: var(--panel);
+ border: 1px solid var(--border);
+ border-radius: 0.625rem;
+ box-shadow: var(--shadow-sm);
+ padding: 2.5rem 1.25rem;
+ text-align: center;
+ font-size: 0.844rem;
+ color: var(--text-3);
+}
diff --git a/frontend/src/components/common/EmptyState.vue b/frontend/src/components/common/EmptyState.vue
new file mode 100644
index 0000000..977db78
--- /dev/null
+++ b/frontend/src/components/common/EmptyState.vue
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/frontend/src/pages/relay/MyTasksPage.vue b/frontend/src/pages/relay/MyTasksPage.vue
index ef0a472..1041eb6 100644
--- a/frontend/src/pages/relay/MyTasksPage.vue
+++ b/frontend/src/pages/relay/MyTasksPage.vue
@@ -8,6 +8,7 @@ import AppShell from '@/layouts/AppShell.vue'
import UserAvatar from '@/components/UserAvatar.vue'
import DropdownSelect from '@/components/DropdownSelect.vue'
import LoadMore from '@/components/common/LoadMore.vue'
+import EmptyState from '@/components/common/EmptyState.vue'
import { useMyTaskStore } from '@/stores/my-task.store'
import { useProjectStore } from '@/stores/project.store'
import { countActive, type MyTaskRow } from '@/mock/relay.mock'
@@ -216,18 +217,12 @@ function loadMore() {
-
+
내 업무를 불러오는 중…
-
-
+
+
{{ view === 'assigned' ? '담당 중인 업무가 없습니다.' : '지시한 업무가 없습니다.' }}
-
+
-
+
활동을 불러오는 중입니다…
-
-
+
+
아직 기록된 활동이 없습니다.
-
+
@@ -366,15 +361,4 @@ const ActIcon = defineComponent({
margin-left: 0.75rem;
}
-/* 로딩/빈 상태 */
-.feed-state {
- background: var(--panel);
- border: 1px solid var(--border);
- border-radius: 0.625rem;
- box-shadow: var(--shadow-sm);
- padding: 2.5rem 1.25rem;
- text-align: center;
- font-size: 0.844rem;
- color: var(--text-3);
-}
diff --git a/frontend/src/pages/relay/ProjectDetailPage.vue b/frontend/src/pages/relay/ProjectDetailPage.vue
index a0a6bbb..fba490a 100644
--- a/frontend/src/pages/relay/ProjectDetailPage.vue
+++ b/frontend/src/pages/relay/ProjectDetailPage.vue
@@ -11,6 +11,7 @@ import UserAvatar from '@/components/UserAvatar.vue'
import DropdownSelect from '@/components/DropdownSelect.vue'
import SegmentedTabs from '@/components/common/SegmentedTabs.vue'
import LoadMore from '@/components/common/LoadMore.vue'
+import EmptyState from '@/components/common/EmptyState.vue'
import { useProjectStore } from '@/stores/project.store'
import { useTaskStore } from '@/stores/task.store'
import type { TaskListQuery, TaskSegment, TaskSort } from '@/types/task'
@@ -243,18 +244,12 @@ const STATUS_LABEL: Record
= {
-
+
업무를 불러오는 중…
-
-
+
+
{{ isFiltered ? '조건에 맞는 업무가 없습니다.' : '아직 등록된 업무가 없습니다. 새 업무를 지시해 보세요.' }}
-
+
= {
text-align: center;
color: var(--text-2);
}
-.state-msg {
- padding: 2.5rem 1.125rem;
- text-align: center;
- font-size: 0.844rem;
- color: var(--text-3);
- border: 1px solid var(--border);
- border-radius: var(--radius);
- background: #fff;
-}
diff --git a/frontend/src/pages/relay/ProjectListPage.vue b/frontend/src/pages/relay/ProjectListPage.vue
index 1089f25..f42a8d8 100644
--- a/frontend/src/pages/relay/ProjectListPage.vue
+++ b/frontend/src/pages/relay/ProjectListPage.vue
@@ -7,6 +7,7 @@ import AppShell from '@/layouts/AppShell.vue'
import UserAvatar from '@/components/UserAvatar.vue'
import DropdownSelect from '@/components/DropdownSelect.vue'
import LoadMore from '@/components/common/LoadMore.vue'
+import EmptyState from '@/components/common/EmptyState.vue'
import { useProjectStore } from '@/stores/project.store'
import type { ProjectListQuery, ProjectSort } from '@/types/project'
@@ -204,18 +205,12 @@ const isFiltered = computed(() => keyword.value.trim() !== '')
-
+
불러오는 중…
-
-
+
+
{{ isFiltered ? '검색 결과가 없습니다.' : '아직 프로젝트가 없습니다. 새 프로젝트를 만들어 보세요.' }}
-
+
@@ -368,10 +363,4 @@ const isFiltered = computed(() => keyword.value.trim() !== '')
width: 1.125rem;
height: 1.125rem;
}
-.list-empty {
- padding: 2.5rem 1.25rem;
- text-align: center;
- color: var(--text-3);
- font-size: 0.844rem;
-}
diff --git a/frontend/src/pages/relay/ProjectMembersPage.vue b/frontend/src/pages/relay/ProjectMembersPage.vue
index f89970a..c286dfa 100644
--- a/frontend/src/pages/relay/ProjectMembersPage.vue
+++ b/frontend/src/pages/relay/ProjectMembersPage.vue
@@ -9,6 +9,7 @@ import UserAvatar from '@/components/UserAvatar.vue'
import DropdownSelect from '@/components/DropdownSelect.vue'
import BaseModal from '@/components/common/BaseModal.vue'
import SegmentedTabs from '@/components/common/SegmentedTabs.vue'
+import EmptyState from '@/components/common/EmptyState.vue'
import { useProjectStore } from '@/stores/project.store'
import { useMemberStore } from '@/stores/member.store'
import { useUser } from '@/composables/useUser'
@@ -325,18 +326,12 @@ onUnmounted(() => window.removeEventListener('keydown', onKeydown))
-
+
멤버를 불러오는 중…
-
-
+
+
표시할 멤버가 없습니다.
-
+
window.removeEventListener('keydown', onKeydown))
}
/* 로딩/빈 상태 메시지 */
-.state-msg {
- padding: 2.5rem 1.125rem;
- text-align: center;
- font-size: 0.844rem;
- color: var(--text-3);
- border: 1px solid var(--border);
- border-radius: var(--radius);
- background: #fff;
-}
/* 역할 변경 드롭다운 */
/* 전역 .list 의 overflow:hidden 이 드롭다운을 잘라내므로, 이 화면에서는 보이도록 해제.