언제 쓰는가
여러 건을 나열하는 모든 화면. 상품 선반, 주문 내역, 문의 목록, 다운로드 목록. 목록이 비는 경우는 예외가 아니라 첫 방문의 기본 상태이므로 처음부터 함께 설계한다.
구조
카드형 목록(상품·강의처럼 그림과 설명이 있는 항목):
<div class="gj-shelf-head">
<h2>{{ __('store.shelf_new') }}</h2>
<a href="{{ route('catalog.index') }}">{{ __('store.shelf_more') }}</a>
</div>
@if ($products->isEmpty())
<x-gujo::empty>{{ __('store.catalog_empty') }}</x-gujo::empty>
@else
<div class="gj-grid">
@foreach ($products as $product)
<x-gujo::product-card :href="route('catalog.show', $product->id)" :title="$product->title" … />
@endforeach
</div>
@endif
표형 목록(주문·문의처럼 상태와 날짜가 중요한 항목):
@if ($orders->isEmpty())
<x-gujo::empty>{{ __('store.orders_empty') }}</x-gujo::empty>
@else
<x-gujo::table :head="[__('store.col_order'), __('store.col_status'), __('store.col_date')]">
@foreach ($orders as $order)
<tr>
<td>{{ $order->id }}</td>
<td><span class="gj-badge gj-badge--ok">{{ __('store.status_paid') }}</span></td>
<td>{{ $order->paid_at?->format('Y-m-d') }}</td>
</tr>
@endforeach
</x-gujo::table>
@endif
- 목록 머리는
.gj-shelf-head(h2 + "더 보기" 링크) 또는.gj-section-head. - 필터·정렬·건수는
.gj-toolbar한 줄에 둔다. 건수는.gj-toolbar .count, 정렬은select. - 분류 칩은
.gj-chips+.gj-chip, 선택된 칩은.is-active. 좌측 정렬은.gj-chips--start. - 카테고리 사이드바가 있는 카탈로그는
.gj-catlayout+.gj-catside. - 빈 상태는
<x-gujo::empty>하나. 문구는 "왜 비었는지 + 다음 행동" 한 문장이고 카피는__('store.catalog_empty')처럼 키로만 둔다.
쓰는 .gj-* 클래스와 Blade 컴포넌트
- 컴포넌트:
<x-gujo::product-card>,<x-gujo::table>,<x-gujo::empty> - 클래스:
.gj-grid,.gj-shelf-head,.gj-toolbar,.gj-chips,.gj-chips--start,.gj-chip,.is-active,.gj-catlayout,.gj-catside,.gj-badge,.gj-badge--ok,.gj-badge--warn
하지 말 것
- 빈 목록에 표 머리글만 남기거나 "데이터가 없습니다" 같은 시스템 말투를 쓰지 않는다.
- 항목 식별에 슬러그를 쓰지 않는다. 링크는 안정 numeric ID 로 만든다(프로젝트 전역 규칙).
- 카드 안에 가격 외의 숫자(할인율 계산식·재고 등)를 늘어놓지 않는다. 카드는 제목·한 줄 설명·가격까지.
.gj-grid열 수를 앱에서 덮어쓰지 않는다. 반응형 규칙은 패키지가 갖는다.
