Oruga Vue 3 패키지 0.14.4와 @oruga-ui/theme-oruga 0.10.0을 사용합니다. 아래 값은 선택적 기본 테마의 값이며, 변경할 수 없는 헤드리스 코어의 값이 아닙니다. MDI 7.4.47 아이콘은 로컬에서 제공합니다. 주변 카탈로그 레이아웃과 폴더 삽화는 독창적으로 제작했습니다.
Oruga는 특정 CSS 프레임워크를 요구하지 않고 Vue 컴포넌트를 제공합니다. 이 예시에서는 Vue 3 패키지와 별도의 Oruga 기본 테마를 함께 사용합니다. 선택한 녹색 태그와 윤곽선이 있는 필드는 해당 테마에서 제공하며, 검색, 선택, 삭제는 컴포넌트 자체의 동작입니다.
라이브러리를 평가할 때는 이 경계를 이해하는 것이 유용합니다. 팀은 컴포넌트 API를 유지하면서 클래스 구성을 바꾸거나 지원되는 다른 테마를 선택할 수 있습니다. 따라서 참고 표에는 녹색 기본 색상을 모든 Oruga 애플리케이션에 공통으로 적용되는 요구 사항으로 설명하지 않고, 테마 패키지와 버전을 명시합니다.
설치된 선택적 테마는 --oruga-primary를 #445e00으로, --oruga-primary-invert를 흰색으로 정의합니다. 위험 상태 색상은 #b60000이며 컨트롤 테두리에는 #dbdbdb를 사용합니다. 컴포넌트의 variant 속성으로 적절한 시맨틱 계열을 선택하므로, 각 필드나 태그에 별도의 CSS 규칙을 지정할 필요가 없습니다.
같은 테마에서 표준 모서리 반경은 4픽셀, 컨트롤 높이는 2.25em이며, 패딩 계산에서는 1픽셀 테두리를 뺍니다. 이러한 값은 컨트롤의 글꼴 크기를 기준으로 하므로 글꼴 크기를 바꾸면 형태도 달라집니다. 테마의 0.5em 간격 값은 컴포넌트 간 관계를 나타내며, 페이지 레이아웃 전체의 간격 스케일을 의미하지는 않습니다.
Oruga UI 디자인 시스템: Oruga가 의도적으로 제공하지 않는 레이아웃을 구성하세요
Oruga가 의도적으로 제공하지 않는 레이아웃을 구성하세요
카탈로그는 폭에 따라 크기가 조정되는 편집기 열과 너비 330px의 카드 열로 구성되며, 760px 미만에서는 세로로 쌓입니다. 페이지 제목에는 시스템 산세리프체를, 카드 제목에는 편집 기록 같은 느낌을 주는 Georgia를 사용합니다. 둘 다 독창적인 선택이며 외부 글꼴 파일은 필요하지 않습니다.
Oruga는 그리드나 유틸리티 프레임워크를 지정하지 않습니다. 따라서 전체 스타일시트에서 패널 여백, 좁은 화면의 안쪽 여백, 줄 바꿈 규칙을 명확히 확인할 수 있습니다. 태그 개수 표시는 분자와 분모를 함께 유지하며, 카드 제목은 메모 이름이 길어져도 줄 바꿈되어 삽입된 페이지가 가로로 밀리지 않습니다.
OTaginput은 선택한 주제 배열을 v-model로 바인딩합니다. 내부 자동 완성 텍스트는 후보 레이블을 필터링하며, 선택한 배열을 바꾸지 않습니다. 구체적인 정의가 있는 독창적인 주제 6개를 어휘 목록에 포함하고, 실시간 카드에는 선택한 주제의 정의만 표시합니다.
기본 검색은 대소문자를 구분하지 않습니다. 로컬 테스트에서는 Color를 입력한 뒤 필터링이 완료될 때까지 기다리고, 결과 옵션을 선택했습니다. 입력 디바운스가 끝나기 전에 바로 확인하면 필터링에 실패한 것처럼 잘못 판단할 수 있습니다. 항목을 선택하면 기존 태그는 유지되고 검색어는 지워집니다.
allow-new=false는 입력한 임의의 문구가 레이블로 추가되지 않도록 합니다. allow-duplicates=false는 기존 레이블을 중복해서 추가하지 못하게 합니다. maxitems=3은 선택 항목의 총개수를 제한하고 개수 표시를 보여줍니다. 각 설정은 통제된 어휘의 서로 다른 측면을 관리합니다.
저장을 시도할 때 주제를 하나 이상 선택했는지 확인합니다. 최대 선택 개수가 최소 선택 요건을 의미하지는 않습니다. 또한 제목 앞뒤 공백을 제거한 뒤 의미 있는 문자가 5자 이상인지 확인하며, 기본 입력의 maxlength는 최대 길이를 80자로 제한합니다.
OField는 노트 제목과 주제에 표시되는 레이블 및 메시지를 제공합니다. 저장에 실패하면 해당 필드에 danger 변형을 적용하고 구체적인 수정 안내를 표시합니다. 주제 안내는 오류가 발생하기 전에 선택 가능한 범위와 어휘 제한을 설명합니다.
기본 태그 입력 드롭다운은 combobox/listbox 패턴을 따릅니다. 이 버전에서는 combobox 역할이 래퍼에 지정되고, 편집 가능한 텍스트 상자는 그 안에 중첩됩니다. 따라서 QA에서는 combobox 역할이 있는 요소 자체를 입력란이라고 가정하지 않고 실제 Search topics 입력란을 채웁니다.
태그 제거 컨트롤은 Oruga의 기본 MDI 아이콘 팩을 사용합니다. 컴포넌트 테마를 불러와도 해당 글꼴은 자동으로 불러오지 않으므로 @mdi/font를 포함해 설정해야 합니다. 독립형 미리보기에서는 원격 글꼴에 의존하지 않도록 로컬 WOFF2 에셋과 필수 아이콘 규칙을 사용합니다.
제거 컨트롤은 접근 가능한 Remove topic 레이블이 있는 실제 버튼으로 유지합니다. 장식용 폴더 일러스트는 해당 컨트롤 아이콘과 무관하므로 보조 기술에서 숨깁니다. 이렇게 하면 장식 요소를 조작 가능한 컨트롤로 오인하지 않습니다.
저장 동작은 앞뒤 공백을 제거한 제목과 선택한 주제 개수를 담은 문장을 기록합니다. 감시자는 제목과 주제 배열을 깊은 수준까지 감시하므로 항목을 제거해도 제목을 바꾼 경우와 마찬가지로 확인 상태가 지워집니다. 현재 스냅샷이 저장된 상태일 때만 저장 버튼이 비활성화됩니다.
노트 지우기는 제목, 선택한 주제 전체, 유효성 검사 시도 여부와 저장 상태를 초기화합니다. 그러면 카드에 Untitled research note와 No topics selected가 표시됩니다. 버튼 뒤에 백엔드, 업로드 또는 게시 작업을 숨기지 않고도 빈 상태에서 편집한 뒤 저장하는 전체 흐름을 확인할 수 있습니다.
Oruga UI 디자인 시스템: 최신 Oruga 등록 방식에 맞춰 컴포넌트를 명시적으로 가져오기
현재 Oruga 등록 방식에 따라 컴포넌트를 명시적으로 가져오세요
검증된 0.14.4 설정은 Oruga 인스턴스를 생성하고 Vue 앱에 설치합니다. App.vue에서는 OField, OInput, OTaginput, OTag, OButton을 명시적으로 가져옵니다. 이는 최신 등록 방식을 따릅니다. 모든 컴포넌트가 전역에 등록된다고 가정하는 이전 예제를 따르면 애플리케이션 설정이 불완전해질 수 있습니다.
테마 README에는 이 기본 테마가 Oruga의 기존 클래스 이름을 사용하고 스타일시트가 필요하며, 별도의 테마 설정 객체는 필요하지 않다고 안내되어 있습니다. 진입점에서는 해당 스타일시트, MDI 에셋, 원래 레이아웃을 순서대로 가져옵니다. 위의 전체 소스 예제와 아래의 Vite 루트에 필요한 모든 항목이 포함되어 있습니다.
OTaginput, OField, OInput, OTag, OButton으로 제한된 어휘와 실시간 카탈로그 카드를 연결합니다.
vue
<script setup>
import {ref,computed,watch} from 'vue';
import {OField,OInput,OTaginput,OButton,OTag} from '@oruga-ui/oruga-next';
const title=ref('Finding a calmer navigation'),topics=ref(['Navigation']),attempted=ref(false),saved=ref('');
const definitions={'Navigation':'Menus, wayfinding and the path through a product.','Typography':'Type hierarchy, reading rhythm and legibility.','Color':'Semantic roles, contrast and theme behavior.','Forms':'Input labels, validation and correction.','Motion':'Transitions, reduced motion and continuity.','Accessibility':'Keyboard flow, semantics and assistive technology.'};
const options=Object.keys(definitions),valid=computed(()=>title.value.trim().length>=5&&topics.value.length>=1&&topics.value.length<=3);
watch([title,topics],()=>saved.value='',{deep:true});
function save(){attempted.value=true;if(valid.value)saved.value=`Saved locally: “${title.value.trim()}” with ${topics.value.length} ${topics.value.length===1?'topic':'topics'}.`}
function reset(){title.value='';topics.value=[];attempted.value=false;saved.value=''}
</script>
<template><main class="catalog-shell"><header><p class="eyebrow">RESEARCH CATALOG · LABEL A NOTE</p><h1>Give the next reader a useful starting point.</h1><p>Name a research note and choose up to three topics from a controlled vocabulary.</p></header><div class="catalog-layout"><section class="editor"><h2>Note details</h2><OField label="Note title" :variant="attempted&&title.trim().length<5?'danger':undefined" :message="attempted&&title.trim().length<5?'Use at least five meaningful characters.':undefined"><OInput v-model="title" maxlength="80" expanded placeholder="What did you learn?"/></OField><OField label="Topics" :variant="attempted&&!topics.length?'danger':undefined" :message="attempted&&!topics.length?'Choose at least one topic.':'Choose 1–3 existing topics; duplicate and new labels are not added.'"><OTaginput v-model="topics" :options="options" :allow-new="false" :allow-duplicates="false" :maxitems="3" open-on-focus :keep-open="false" expanded variant="primary" placeholder="Search topics" aria-close-label="Remove topic"><template #empty>No matching topic. Try Color, Forms or Motion.</template></OTaginput></OField><div class="actions"><OButton variant="primary" @click="save" :disabled="!!saved">Save local note</OButton><OButton @click="reset">Clear note</OButton></div><p role="status" class="result">{{saved||'The preview keeps only local page state.'}}</p><h3>Vocabulary guide</h3><dl class="vocabulary"><div v-for="(meaning,name) in definitions" :key="name"><dt>{{name}}</dt><dd>{{meaning}}</dd></div></dl></section><aside class="note-card"><div class="folder-art" aria-hidden="true"><i></i><b></b><span></span></div><p class="eyebrow">CATALOG CARD PREVIEW</p><h2>{{title.trim()||'Untitled research note'}}</h2><div class="topic-tags"><OTag v-for="topic in topics" :key="topic" variant="primary">{{topic}}</OTag><span v-if="!topics.length" class="empty-topics">No topics selected</span></div><p class="card-label">This note will appear under</p><ul><li v-for="topic in topics" :key="topic"><strong>{{topic}}</strong><span>{{definitions[topic]}}</span></li></ul><p class="card-foot">Original sample note · no upload or publishing</p></aside></div></main></template>
Oruga는 필수 그리드 시스템을 제공하지 않으므로 이 레이아웃은 애플리케이션에서 명시적으로 정의합니다 CSS.
좁은 화면에서도 카운터 텍스트가 한 줄로 표시됩니다.
04
Oruga UI 디자인 시스템 AI 에이전트 설정
구현 시작점
검증된 Oruga 0.14.4, 선택 사항인 기본 테마 0.10.0, MDI 7.4.47을 사용합니다. 컴포넌트는 명시적으로 가져오며 기본 테마에는 추가 JavaScript 테마 설정이 필요하지 않습니다.
자바스크립트
// npm create vite@latest oruga-catalog -- --template vue
// cd oruga-catalog && npm install
// npm install @oruga-ui/[email protected] @oruga-ui/[email protected] @mdi/[email protected]
// Save the complete examples as src/App.vue and src/style.css.
// src/main.js:
import {createApp} from 'vue';
import {createOruga} from '@oruga-ui/oruga-next';
import '@oruga-ui/theme-oruga/style.css';
import '@mdi/font/css/materialdesignicons.css';
import './style.css';
import App from './App.vue';
createApp(App).use(createOruga()).mount('#app');
// index.html: <div id="app"></div><script type="module" src="/src/main.js"></script>
// npm run dev
프로젝트를 위한 프롬프트
에이전트 프롬프트
Oruga 0.14.4 연구 노트 카탈로그와 0.10.0 테마로 시작합니다. 6개 주제 어휘를 사용하는 OTaginput의 제어된 선택 방식, 대소문자를 구분하지 않는 검색, 새 태그 및 중복 태그 비활성화, 최대 3개 태그 제한을 유지합니다. 실시간 주제 정의와 제목 유효성 검사를 저장된 스냅샷에 연결하고, 변경 사항이 있으면 저장 확인 상태를 지웁니다. createOruga, 테마 CSS, 로컬 MDI 에셋 설정을 포함합니다. 빈 초안으로 초기화하고 제품 비교 데이터나 원격 카탈로그 업데이트를 임의로 추가하지 않습니다.
05
Oruga UI 디자인 시스템 출처와 범위
선택 사항인 기본 테마 0.10.0을 사용하는 Oruga 0.14.4입니다. 어휘와 카탈로그 일러스트는 독창적으로 제작했습니다. 저장은 업로드, 게시 또는 새로고침 후에도 유지되는 기능 없이 로컬 페이지 상태만 변경합니다.