| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- <template>
- <div class="grid-4">
- <div
- v-for="s in students"
- :key="s.userId"
- class="student-card"
- :class="['status-' + s.status]"
- @click="$emit('click', s)"
- >
- <div class="avatar" :class="'avatar-' + s.status">
- {{ s.name.charAt(0) }}
- </div>
- <span class="name">{{ s.name }}</span>
- <span v-if="s.status === 'submitted'" class="indicator check">✓</span>
- <span v-else-if="s.status === 'unsubmitted'" class="indicator dot pulse" />
- <span v-else class="indicator dash">—</span>
- </div>
- </div>
- </template>
- <script lang="ts" setup>
- import type { ClassStudentSummary } from './types'
- defineProps<{ students: ClassStudentSummary[] }>()
- defineEmits<{ click: [student: ClassStudentSummary] }>()
- </script>
- <style lang="scss" scoped>
- .grid-4 {
- display: grid;
- grid-template-columns: repeat(4, minmax(0, 1fr));
- gap: 12px;
- }
- .student-card {
- display: flex;
- align-items: center;
- gap: 10px;
- padding: 8px 12px;
- border-radius: 8px;
- cursor: pointer;
- transition: box-shadow .15s ease;
- background: #fff;
- border: 2px solid transparent;
- &:hover { box-shadow: 0 2px 8px rgba(0,0,0,.08); }
- &.status-submitted { border-color: #facc15; }
- &.status-unsubmitted { border-color: #fde68a; }
- &.status-not_started {
- background: #f3f4f6;
- border: 2px dashed #9ca3af;
- }
- }
- .avatar {
- flex-shrink: 0;
- width: 32px; height: 32px;
- border-radius: 50%;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 12px;
- font-weight: 600;
- }
- .avatar-submitted { background: #facc15; color: #111827; }
- .avatar-unsubmitted { background: #fef3c7; color: #92400e; }
- .avatar-not_started { background: #e5e7eb; color: #6b7280; }
- .name {
- flex: 1;
- font-size: 14px;
- font-weight: 500;
- color: #111827;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .status-not_started .name { color: #9ca3af; }
- .indicator {
- flex-shrink: 0;
- font-size: 12px;
- }
- .indicator.check { color: #ca8a04; font-weight: 600; }
- .indicator.dash { color: #9ca3af; }
- .indicator.dot.pulse {
- width: 8px; height: 8px;
- border-radius: 50%;
- background: #fbbf24;
- animation: pulse 1.5s ease-in-out infinite;
- }
- @keyframes pulse {
- 0%, 100% { opacity: 1; }
- 50% { opacity: .4; }
- }
- </style>
|