Quiet Luxury редизайн элементов #1440 и #896 — design spec

Дата: 2026-05-12 Скоуп: буквально два элемента из Dev Element Indices. Цель: привести два визуально «тяжёлых» / выпадающих из Quiet Luxury (Portal Redesign I1) элемента к языку токенов tokens.css. Связанные документы: Portal Redesign — Quiet Luxury (I1), Dev Element Indices. Status: approved sections (1–5), pending user review of written spec.


1. Контекст и проблема

1.1. Элемент #1440 — span.card-check__box в ProjectCard.vue

1.2. Элемент #896 — v-text-field «Название проекта» в NewProjectDialog.vue

1.3. Известные близнецы (вне области по решению заказчика)


2. Архитектура

Узкая CSS / prop-правка, без новых компонентов и primitives:

Никаких изменений в tokens.css, app.css, motion.css, typography.css. Используем только существующие токены и Vuetify 3 API.


3. Точная реализация

3.1. #1440 — новый <style scoped> в ProjectCard.vue

Полная замена текущего блока (current lines 132–172):

<style scoped>
.project-card.paused {
    opacity: 0.75;
}
.card-check {
    display: inline-flex;
    align-items: center;
    cursor: pointer;
    padding: 4px;
}
.card-check input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.card-check__box {
    width: 16px;
    height: 16px;
    border: 1px solid var(--liderra-line);
    border-radius: var(--radius-6);
    background: var(--liderra-surface);
    display: inline-block;
    position: relative;
    transition:
        border-color 200ms cubic-bezier(0.16, 1, 0.3, 1),
        background-color 200ms cubic-bezier(0.16, 1, 0.3, 1);
}
.card-check:hover .card-check__box {
    border-color: var(--liderra-line-strong);
}
.card-check input:focus-visible + .card-check__box {
    outline: 2px solid var(--liderra-teal);
    outline-offset: 2px;
}
.card-check input:checked + .card-check__box {
    background: rgba(15, 110, 86, 0.10);
    border-color: var(--liderra-teal);
}
.card-check input:checked + .card-check__box::after {
    content: '';
    position: absolute;
    left: 4px;
    top: 0;
    width: 5px;
    height: 9px;
    border: solid var(--liderra-teal);
    border-width: 0 1.5px 1.5px 0;
    transform: rotate(45deg);
}
</style>

Delta vs. текущий код:

3.2. #896 — расширение шаблона + новый <style scoped> в NewProjectDialog.vue

Template edit на line 59 — заменить:

<v-text-field v-model="form.name" label="Название проекта" :error-messages="errors.name" />

на:

<v-text-field
    v-model="form.name"
    label="Название проекта"
    variant="outlined"
    density="compact"
    color="primary"
    rounded="lg"
    class="ld-input-quiet"
    :error-messages="errors.name"
/>

Новый <style scoped> блок в конце файла (после </script> line 208):

<style scoped>
.ld-input-quiet :deep(.v-field__outline__start),
.ld-input-quiet :deep(.v-field__outline__end),
.ld-input-quiet :deep(.v-field__outline__notch::before),
.ld-input-quiet :deep(.v-field__outline__notch::after) {
    border-color: var(--liderra-line);
    transition: border-color 200ms cubic-bezier(0.16, 1, 0.3, 1);
}
.ld-input-quiet:hover :deep(.v-field__outline__start),
.ld-input-quiet:hover :deep(.v-field__outline__end),
.ld-input-quiet:hover :deep(.v-field__outline__notch::before),
.ld-input-quiet:hover :deep(.v-field__outline__notch::after) {
    border-color: var(--liderra-line-strong);
}
.ld-input-quiet :deep(.v-field--focused .v-field__outline__start),
.ld-input-quiet :deep(.v-field--focused .v-field__outline__end),
.ld-input-quiet :deep(.v-field--focused .v-field__outline__notch::before),
.ld-input-quiet :deep(.v-field--focused .v-field__outline__notch::after) {
    border-color: var(--liderra-teal);
}
</style>

Обоснования:


4. Тестирование и верификация

4.1. Vitest

4.2. Histoire

4.3. A11y

4.4. Lint / Type-check

4.5. Manual smoke

4.6. Pre-commit

lefthook stages (job'ы из репозитория — lefthook.yml):

Полный прогон lefthook run pre-commit перед коммитом.


5. Out-of-scope (явно)


6. Риски и допущения

  1. :deep() против внутренних Vuetify-classes.v-field__outline__start/end/notch::before/::after зависит от внутренней Vuetify 3 SFC-структуры. Риск ломки при минорном bump'е Vuetify. Митигация: класс .ld-input-quiet локализует override, при обновлении Vuetify нужен manual recheck (не верифицировал точную совместимость с Vuetify 3.12 — assumption на основе официальной документации Vuetify 3.x).
  2. focus-visible на скрытом <input> — input position: absolute; opacity: 0; pointer-events: none, но focusable (нет tabindex="-1", нет disabled). :focus-visible должен срабатывать при Tab. Если в браузере Safari < 15.4 — :focus-visible не поддерживается, fallback на :focus для тех браузеров (не добавляем — рынок Safari < 15.4 ничтожен, см. caniuse).
  3. rounded="lg" в Vuetify 3 = 8px — допущение по официальной документации rounded prop'а. Не верифицировал в коде Vuetify 3.12; если значение отличается, override через CSS :deep(.v-field) { border-radius: var(--radius-8); }.
  4. color="primary" подсветит label и caret в teal — допущение на основе того, что vuetify.ts определяет primary: var(--liderra-teal). Re-Read app/resources/js/plugins/vuetify.ts обязателен в implementation phase.
  5. Vitest snapshot-тесты, если есть — могут зафейлиться на новой структуре props (variant="outlined" добавит классы Vuetify в render output). Митигация: обновить snapshot'ы в plan task'е, не считать regression'ом.

7. Definition of Done


8. Открытые вопросы — отсутствуют

В этой спецификации нет TBD / TODO / placeholder. Область фиксирована.