@things-factory/board-ui 10.0.0-beta.88 → 10.0.0-beta.89

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -68,27 +68,53 @@ let BoardTileList = class BoardTileList extends LitElement {
68
68
 
69
69
  [card] > a {
70
70
  display: flex;
71
+ align-items: center;
72
+ justify-content: center;
71
73
  clip-path: border-box;
74
+ padding: var(--spacing-large);
75
+ box-sizing: border-box;
72
76
  }
73
77
 
74
78
  [card]:hover {
75
79
  cursor: pointer;
76
80
  }
77
81
 
82
+ /* 데스크탑 (hover 가능 + 정밀 포인터): 액션 아이콘 fade-in.
83
+ * favored 별은 *상태 표시* 라 호버 무관하게 보임 — 어떤 보드가 즐겨찾기인지
84
+ * 한눈에. unfavored 별 + info 만 호버 시 노출.
85
+ * 모바일/터치 환경에서는 hover 가 없으므로 이 블록이 미적용 → 기본 동작
86
+ * (별/메뉴 항상 노출) 그대로 유지. */
87
+ @media (hover: hover) and (pointer: fine) {
88
+ md-icon[iconBtn]:not([favored]) {
89
+ opacity: 0;
90
+ transition: opacity 0.2s ease;
91
+ }
92
+
93
+ [card]:hover md-icon[iconBtn] {
94
+ opacity: 1;
95
+ }
96
+ }
97
+
78
98
  [name] {
79
99
  text-overflow: ellipsis;
80
100
  white-space: nowrap;
81
101
  overflow: hidden;
82
102
  margin-top: var(--spacing-small);
83
- width: calc(100% - 45px);
103
+ margin-left: var(--spacing-large);
104
+ /* 좌측 inset (margin-left) + 우측 액션 영역 (45px) + 우측 inset = 양쪽 대칭 */
105
+ width: calc(100% - 45px - var(--spacing-large) * 2);
84
106
  color: var(--md-sys-color-on-background);
85
107
  font-weight: bolder;
86
108
  font-size: var(--fontsize-small);
87
109
  }
88
110
 
89
111
  img {
90
- flex: 1;
112
+ max-width: 100%;
113
+ max-height: 100%;
114
+ width: auto;
115
+ height: auto;
91
116
  object-fit: contain;
117
+ border-radius: var(--card-list-thumbnail-radius);
92
118
  }
93
119
 
94
120
  md-icon[iconBtn] {
@@ -98,8 +124,10 @@ let BoardTileList = class BoardTileList extends LitElement {
98
124
  color: var(--board-list-star-color);
99
125
  font-size: 1.4em;
100
126
  }
101
- md-icon[info] {
127
+ /* info 가 render 순서상 첫째 = float right 시 가장 우측 — 카드 우측 inset 적용 */
128
+ md-icon[iconBtn][info] {
102
129
  color: var(--md-sys-color-primary);
130
+ margin-right: var(--spacing-large);
103
131
  }
104
132
 
105
133
  md-icon[iconBtn][favored],
@@ -118,14 +146,6 @@ let BoardTileList = class BoardTileList extends LitElement {
118
146
  height: calc(100% - 25px);
119
147
  }
120
148
 
121
- :host > *:hover [info] {
122
- opacity: 1;
123
- -webkit-transition: opacity 0.8s;
124
- -moz-transition: opacity 0.8s;
125
- -o-transition: opacity 0.8s;
126
- transition: opacity 0.8s;
127
- }
128
-
129
149
  [draggable='true'] {
130
150
  cursor: grab;
131
151
  transition: opacity 0.2s ease, transform 0.2s ease;
@@ -412,7 +432,9 @@ let BoardTileList = class BoardTileList extends LitElement {
412
432
  : nothing}
413
433
  ${repeat(boards, board => board.id, board => html `
414
434
  <div card draggable="true" id=${board.id}>
415
- <a href="board-viewer/${board.id}"> <img src=${board.thumbnail} /> </a>
435
+ <a href="board-viewer/${board.id}">
436
+ <img src=${board.thumbnail} />
437
+ </a>
416
438
 
417
439
  <div name>${board.name}</div>
418
440
  <!-- <div description>${board.description}</div> -->
@@ -1 +1 @@
1
- {"version":3,"file":"board-tile-list.js","sourceRoot":"","sources":["../../client/board-list/board-tile-list.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, PropertyValues, nothing } from 'lit'\nimport { customElement, property, state, query } from 'lit/decorators.js'\nimport { repeat } from 'lit/directives/repeat.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\n\nimport { privileged } from '@things-factory/auth-base/dist-client/index.js'\n\n@customElement('board-tile-list')\nexport class BoardTileList extends LitElement {\n static styles = [\n css`\n :host {\n overflow: auto;\n padding: var(--popup-content-padding);\n display: grid;\n background-color: var(--md-sys-color-background);\n\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n grid-auto-rows: var(--card-list-rows-height);\n grid-gap: 20px;\n }\n\n [card] {\n position: relative;\n align-items: center;\n overflow: hidden;\n }\n\n [card][create] {\n overflow: visible;\n background-color: initial;\n }\n\n [card][import-card] > a {\n display: flex;\n align-items: center;\n justify-content: center;\n height: calc(100% - 25px);\n border: 1px dashed var(--md-sys-color-outline-variant, #b8c2cc);\n border-radius: var(--card-list-border-radius, 8px);\n text-decoration: none;\n color: var(--md-sys-color-on-secondary-container, #555);\n background: var(--md-sys-color-surface-container, #fff);\n box-sizing: border-box;\n }\n [card][import-card] > a:hover {\n border-color: var(--md-sys-color-primary, #2a64d8);\n color: var(--md-sys-color-primary, #2a64d8);\n background: var(--md-sys-color-primary-container, #eaf2ff);\n }\n [card][import-card] md-icon {\n font-size: 48px;\n --md-icon-size: 48px;\n }\n\n [card] > a {\n display: flex;\n clip-path: border-box;\n }\n\n [card]:hover {\n cursor: pointer;\n }\n\n [name] {\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n margin-top: var(--spacing-small);\n width: calc(100% - 45px);\n color: var(--md-sys-color-on-background);\n font-weight: bolder;\n font-size: var(--fontsize-small);\n }\n\n img {\n flex: 1;\n object-fit: contain;\n }\n\n md-icon[iconBtn] {\n float: right;\n margin-top: -20px;\n margin-left: 2px;\n color: var(--board-list-star-color);\n font-size: 1.4em;\n }\n md-icon[info] {\n color: var(--md-sys-color-primary);\n }\n\n md-icon[iconBtn][favored],\n md-icon[info]:hover {\n color: var(--board-list-star-active-color);\n }\n\n a {\n display: block;\n border-radius: var(--card-list-border-radius);\n border: var(--border-dim-color);\n box-sizing: border-box;\n color: var(--card-list-color);\n background-color: var(--card-list-background-color);\n margin: 0px;\n height: calc(100% - 25px);\n }\n\n :host > *:hover [info] {\n opacity: 1;\n -webkit-transition: opacity 0.8s;\n -moz-transition: opacity 0.8s;\n -o-transition: opacity 0.8s;\n transition: opacity 0.8s;\n }\n\n [draggable='true'] {\n cursor: grab;\n transition: opacity 0.2s ease, transform 0.2s ease;\n }\n\n [card].dragging {\n opacity: 0.3;\n transform: scale(0.95);\n }\n\n [card].drop-before {\n border-left: 3px solid var(--md-sys-color-primary);\n }\n\n [card].drop-after {\n border-right: 3px solid var(--md-sys-color-primary);\n }\n\n [card].flip-moving {\n transition: transform 1s cubic-bezier(0.25, 0.1, 0.25, 1);\n }\n\n @keyframes drop-land {\n 0% {\n opacity: 0;\n transform: scale(0.9);\n }\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n }\n\n [card].flip-dropped-hidden {\n opacity: 0;\n }\n\n [card].flip-dropped {\n animation: drop-land 0.5s cubic-bezier(0.22, 0.6, 0.36, 1);\n }\n\n @keyframes highlight-sweep {\n 0% {\n background: linear-gradient(90deg, var(--md-sys-color-primary-container) 0%, transparent 0%);\n box-shadow: 0 0 8px 2px var(--md-sys-color-primary);\n }\n 50% {\n background: linear-gradient(90deg, transparent 0%, var(--md-sys-color-primary-container) 50%, transparent 100%);\n box-shadow: 0 0 12px 3px var(--md-sys-color-primary);\n }\n 100% {\n background: transparent;\n box-shadow: none;\n }\n }\n\n @keyframes border-pulse {\n 0%,\n 100% {\n outline: 2px solid transparent;\n }\n 25%,\n 75% {\n outline: 2px solid var(--md-sys-color-primary);\n }\n }\n\n @keyframes subtle-bounce {\n 0% {\n transform: scale(1);\n }\n 30% {\n transform: scale(1.03);\n }\n 100% {\n transform: scale(1);\n }\n }\n\n @keyframes surface-flash {\n 0% {\n background-color: var(--md-sys-color-primary-container);\n }\n 100% {\n background-color: transparent;\n }\n }\n\n [card].anim-sweep {\n animation: highlight-sweep 1.8s ease;\n border-radius: 4px;\n }\n\n [card].anim-pulse {\n animation: border-pulse 1.2s ease;\n }\n\n [card].anim-bounce {\n animation: subtle-bounce 0.8s ease;\n }\n\n [card].anim-flash {\n animation: surface-flash 1.5s ease-out;\n }\n\n `\n ]\n\n @property({ type: Array }) boards: any[] = []\n @property({ type: Array }) favorites: any[] = []\n @property({ type: Array }) groups: any[] = []\n @property({ type: String }) group?: string\n @property({ type: Boolean }) creatable?: boolean = false\n @property({ type: String, attribute: 'search-text' }) searchText?: string\n @property({ type: Boolean, attribute: 'reorderable' }) reorderable: boolean = false\n @property({ type: Array }) updatedIds: string[] = []\n\n private _draggedId: string | null = null\n private _dropTargetId: string | null = null\n private _dropSide: 'before' | 'after' | null = null\n\n connectedCallback() {\n super.connectedCallback()\n\n if (this.reorderable) {\n this.renderRoot.addEventListener('dragstart', (e: Event) => {\n const target = (e.target as HTMLElement).closest('[card]') as HTMLElement | null\n if (!target?.id) return\n\n this._draggedId = target.id\n target.classList.add('dragging')\n ;(e as DragEvent).dataTransfer!.effectAllowed = 'move'\n ;(e as DragEvent).dataTransfer?.setData('text/plain', target.id)\n })\n\n this.renderRoot.addEventListener('dragover', (e: Event) => {\n e.preventDefault()\n ;(e as DragEvent).dataTransfer!.dropEffect = 'move'\n\n const target = (e.target as HTMLElement).closest('[card]') as HTMLElement | null\n if (!target?.id || target.id === this._draggedId) return\n\n const targetRect = target.getBoundingClientRect()\n const mousePos = (e as DragEvent).clientX - targetRect.left\n const side = mousePos < targetRect.width / 2 ? 'before' : 'after'\n\n if (this._dropTargetId !== target.id || this._dropSide !== side) {\n this._clearDropIndicator()\n this._dropTargetId = target.id\n this._dropSide = side\n target.classList.add(side === 'before' ? 'drop-before' : 'drop-after')\n }\n })\n\n this.renderRoot.addEventListener('dragleave', (e: Event) => {\n const target = (e.target as HTMLElement).closest('[card]') as HTMLElement | null\n if (target?.id === this._dropTargetId) {\n const related = (e as DragEvent).relatedTarget as HTMLElement | null\n if (!related || !target.contains(related)) {\n this._clearDropIndicator()\n }\n }\n })\n\n this.renderRoot.addEventListener('drop', (e: Event) => {\n e.preventDefault()\n\n // drop 이벤트에서 직접 타겟과 방향을 계산 (dragleave가 먼저 발생해 상태를 지울 수 있으므로)\n const dropTarget = (e.target as HTMLElement).closest('[card]') as HTMLElement | null\n let dropTargetId = this._dropTargetId\n let dropSide = this._dropSide\n\n if (dropTarget?.id && dropTarget.id !== this._draggedId) {\n dropTargetId = dropTarget.id\n const rect = dropTarget.getBoundingClientRect()\n dropSide = (e as DragEvent).clientX - rect.left < rect.width / 2 ? 'before' : 'after'\n }\n\n this._clearDropIndicator()\n\n const draggedEl = this._draggedId ? this.renderRoot.querySelector(`[card][id=\"${this._draggedId}\"]`) : null\n if (draggedEl) {\n draggedEl.classList.remove('dragging')\n }\n\n if (!this._draggedId || !dropTargetId || this._draggedId === dropTargetId) {\n this._resetDragState()\n return\n }\n\n // 배열 재정렬\n const boards = [...this.boards]\n const draggedIndex = boards.findIndex(b => b.id === this._draggedId)\n if (draggedIndex === -1) {\n this._resetDragState()\n return\n }\n\n const draggedBoardId = this._draggedId\n const [dragged] = boards.splice(draggedIndex, 1)\n let targetIndex = boards.findIndex(b => b.id === dropTargetId)\n if (dropSide === 'after') targetIndex++\n boards.splice(targetIndex, 0, dragged)\n\n this._resetDragState()\n\n // FLIP 애니메이션: 이전 위치 기록\n const cards = this.renderRoot.querySelectorAll('[card][id]')\n const firstPositions = new Map<string, DOMRect>()\n cards.forEach(card => {\n firstPositions.set(card.id, card.getBoundingClientRect())\n })\n\n // optimistic update → Lit 렌더\n this.boards = boards\n\n this.updateComplete.then(() => {\n const updatedCards = this.renderRoot.querySelectorAll('[card][id]')\n let droppedEl: HTMLElement | null = null\n\n updatedCards.forEach(card => {\n const first = firstPositions.get(card.id)\n if (!first) return\n\n const last = card.getBoundingClientRect()\n const dx = first.left - last.left\n const dy = first.top - last.top\n\n const el = card as HTMLElement\n\n if (card.id === draggedBoardId) {\n // 드래그한 카드: 슬라이딩 완료 후 착지하도록 일단 숨김\n el.classList.add('flip-dropped-hidden')\n droppedEl = el\n } else {\n // 밀려나는 카드: 이전 위치에서 새 위치로 슬라이딩\n if (dx === 0 && dy === 0) return\n\n // Invert: 이전 위치로 되돌림\n el.style.transform = `translate(${dx}px, ${dy}px)`\n el.style.transition = 'none'\n\n requestAnimationFrame(() => {\n el.classList.add('flip-moving')\n el.style.transform = ''\n el.style.transition = ''\n\n el.addEventListener(\n 'transitionend',\n () => {\n el.classList.remove('flip-moving')\n },\n { once: true }\n )\n })\n }\n })\n\n // 밀려나는 카드 슬라이딩 완료 후 드래그한 카드 착지 → 착지 완료 후 이벤트 발송\n const boardIds = boards.map(b => b.id)\n const dispatchReordered = () => {\n this.dispatchEvent(\n new CustomEvent('reordered', {\n detail: {\n groupId: this.group,\n boardIds,\n movedId: draggedBoardId\n }\n })\n )\n }\n\n if (droppedEl) {\n setTimeout(() => {\n ;(droppedEl as HTMLElement).classList.remove('flip-dropped-hidden')\n ;(droppedEl as HTMLElement).classList.add('flip-dropped')\n ;(droppedEl as HTMLElement).addEventListener(\n 'animationend',\n () => {\n ;(droppedEl as HTMLElement).classList.remove('flip-dropped')\n dispatchReordered()\n },\n { once: true }\n )\n }, 500)\n } else {\n dispatchReordered()\n }\n })\n })\n\n this.renderRoot.addEventListener('dragend', (e: Event) => {\n this._clearDropIndicator()\n const target = (e.target as HTMLElement).closest('[card]')\n if (target) target.classList.remove('dragging')\n this._resetDragState()\n })\n }\n }\n\n private _clearDropIndicator() {\n if (this._dropTargetId) {\n const el = this.renderRoot.querySelector(`[card][id=\"${this._dropTargetId}\"]`)\n if (el) {\n el.classList.remove('drop-before', 'drop-after')\n }\n }\n this._dropTargetId = null\n this._dropSide = null\n }\n\n private _resetDragState() {\n this._draggedId = null\n this._dropTargetId = null\n this._dropSide = null\n }\n\n render() {\n const boards = this.boards || []\n\n return html`\n ${this.creatable\n ? privileged(\n { privilege: 'mutation', category: 'board' },\n html`\n <div card import-card>\n <a href=\"board-create\" title=${i18next.t('text.create board') || 'Create New Board'}>\n <md-icon>add_circle_outline</md-icon>\n </a>\n <div name>${i18next.t('label.create board') || 'Create Board'}</div>\n </div>\n `\n )\n : nothing}\n ${repeat(\n boards,\n board => board.id,\n board => html`\n <div card draggable=\"true\" id=${board.id}>\n <a href=\"board-viewer/${board.id}\"> <img src=${board.thumbnail} /> </a>\n\n <div name>${board.name}</div>\n <!-- <div description>${board.description}</div> -->\n\n <md-icon\n iconBtn\n info\n @click=${e => {\n this.infoBoard(board)\n e.preventDefault()\n }}\n >info</md-icon\n >\n\n ${(this.favorites || []).includes(board.id)\n ? html` <md-icon iconBtn favored @click=${e => this.removeFavorite(board.id)}>star</md-icon> `\n : html` <md-icon iconBtn @click=${e => this.addFavorite(board.id)}>star_border</md-icon> `}\n </div>\n `\n )}\n `\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('updatedIds') && this.updatedIds.length > 0) {\n const animClasses = ['anim-sweep', 'anim-pulse', 'anim-bounce', 'anim-flash']\n\n for (const id of this.updatedIds) {\n const card = this.renderRoot.querySelector(`[card][id=\"${id}\"]`)\n if (!card) continue\n\n const animClass = animClasses[Math.floor(Math.random() * animClasses.length)]\n card.classList.add(animClass)\n card.addEventListener(\n 'animationend',\n () => {\n card.classList.remove(animClass)\n },\n { once: true }\n )\n }\n }\n }\n\n infoBoard(board) {\n this.dispatchEvent(\n new CustomEvent('info-board', {\n detail: board\n })\n )\n }\n\n async removeFavorite(boardId) {\n await client.mutate({\n mutation: gql`\n mutation {\n deleteFavorite(routing: \"${boardId}\")\n }\n `\n })\n\n this.refreshFavorites()\n }\n\n async addFavorite(boardId) {\n await client.mutate({\n mutation: gql`\n mutation {\n createFavorite(favorite: {\n routing: \"${boardId}\"\n }) {\n id\n routing\n }\n }\n `\n })\n\n this.refreshFavorites()\n }\n\n async refreshFavorites() {\n this.dispatchEvent(new CustomEvent('refresh-favorites'))\n }\n}\n"]}
1
+ {"version":3,"file":"board-tile-list.js","sourceRoot":"","sources":["../../client/board-list/board-tile-list.ts"],"names":[],"mappings":";AAAA,OAAO,4BAA4B,CAAA;AAEnC,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAkB,OAAO,EAAE,MAAM,KAAK,CAAA;AACpE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAgB,MAAM,mBAAmB,CAAA;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AAEjD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAE,UAAU,EAAE,MAAM,gDAAgD,CAAA;AAGpE,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,UAAU;IAAtC;;QA2OsB,WAAM,GAAU,EAAE,CAAA;QAClB,cAAS,GAAU,EAAE,CAAA;QACrB,WAAM,GAAU,EAAE,CAAA;QAEhB,cAAS,GAAa,KAAK,CAAA;QAED,gBAAW,GAAY,KAAK,CAAA;QACxD,eAAU,GAAa,EAAE,CAAA;QAE5C,eAAU,GAAkB,IAAI,CAAA;QAChC,kBAAa,GAAkB,IAAI,CAAA;QACnC,cAAS,GAA8B,IAAI,CAAA;IAmTrD,CAAC;aAxiBQ,WAAM,GAAG;QACd,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsOF;KACF,AAxOY,CAwOZ;IAeD,iBAAiB;QACf,KAAK,CAAC,iBAAiB,EAAE,CAAA;QAEzB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,WAAW,EAAE,CAAC,CAAQ,EAAE,EAAE;gBACzD,MAAM,MAAM,GAAI,CAAC,CAAC,MAAsB,CAAC,OAAO,CAAC,QAAQ,CAAuB,CAAA;gBAChF,IAAI,CAAC,MAAM,EAAE,EAAE;oBAAE,OAAM;gBAEvB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,EAAE,CAAA;gBAC3B,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAC/B;gBAAC,CAAe,CAAC,YAAa,CAAC,aAAa,GAAG,MAAM,CACrD;gBAAC,CAAe,CAAC,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,EAAE,CAAC,CAAA;YAClE,CAAC,CAAC,CAAA;YAEF,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,UAAU,EAAE,CAAC,CAAQ,EAAE,EAAE;gBACxD,CAAC,CAAC,cAAc,EAAE,CACjB;gBAAC,CAAe,CAAC,YAAa,CAAC,UAAU,GAAG,MAAM,CAAA;gBAEnD,MAAM,MAAM,GAAI,CAAC,CAAC,MAAsB,CAAC,OAAO,CAAC,QAAQ,CAAuB,CAAA;gBAChF,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,MAAM,CAAC,EAAE,KAAK,IAAI,CAAC,UAAU;oBAAE,OAAM;gBAExD,MAAM,UAAU,GAAG,MAAM,CAAC,qBAAqB,EAAE,CAAA;gBACjD,MAAM,QAAQ,GAAI,CAAe,CAAC,OAAO,GAAG,UAAU,CAAC,IAAI,CAAA;gBAC3D,MAAM,IAAI,GAAG,QAAQ,GAAG,UAAU,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAA;gBAEjE,IAAI,IAAI,CAAC,aAAa,KAAK,MAAM,CAAC,EAAE,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;oBAChE,IAAI,CAAC,mBAAmB,EAAE,CAAA;oBAC1B,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,EAAE,CAAA;oBAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;oBACrB,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,YAAY,CAAC,CAAA;gBACxE,CAAC;YACH,CAAC,CAAC,CAAA;YAEF,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,WAAW,EAAE,CAAC,CAAQ,EAAE,EAAE;gBACzD,MAAM,MAAM,GAAI,CAAC,CAAC,MAAsB,CAAC,OAAO,CAAC,QAAQ,CAAuB,CAAA;gBAChF,IAAI,MAAM,EAAE,EAAE,KAAK,IAAI,CAAC,aAAa,EAAE,CAAC;oBACtC,MAAM,OAAO,GAAI,CAAe,CAAC,aAAmC,CAAA;oBACpE,IAAI,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;wBAC1C,IAAI,CAAC,mBAAmB,EAAE,CAAA;oBAC5B,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAA;YAEF,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAQ,EAAE,EAAE;gBACpD,CAAC,CAAC,cAAc,EAAE,CAAA;gBAElB,6DAA6D;gBAC7D,MAAM,UAAU,GAAI,CAAC,CAAC,MAAsB,CAAC,OAAO,CAAC,QAAQ,CAAuB,CAAA;gBACpF,IAAI,YAAY,GAAG,IAAI,CAAC,aAAa,CAAA;gBACrC,IAAI,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAA;gBAE7B,IAAI,UAAU,EAAE,EAAE,IAAI,UAAU,CAAC,EAAE,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;oBACxD,YAAY,GAAG,UAAU,CAAC,EAAE,CAAA;oBAC5B,MAAM,IAAI,GAAG,UAAU,CAAC,qBAAqB,EAAE,CAAA;oBAC/C,QAAQ,GAAI,CAAe,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAA;gBACvF,CAAC;gBAED,IAAI,CAAC,mBAAmB,EAAE,CAAA;gBAE1B,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,cAAc,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;gBAC3G,IAAI,SAAS,EAAE,CAAC;oBACd,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;gBACxC,CAAC;gBAED,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,UAAU,KAAK,YAAY,EAAE,CAAC;oBAC1E,IAAI,CAAC,eAAe,EAAE,CAAA;oBACtB,OAAM;gBACR,CAAC;gBAED,SAAS;gBACT,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;gBAC/B,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,UAAU,CAAC,CAAA;gBACpE,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;oBACxB,IAAI,CAAC,eAAe,EAAE,CAAA;oBACtB,OAAM;gBACR,CAAC;gBAED,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,CAAA;gBACtC,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAA;gBAChD,IAAI,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,YAAY,CAAC,CAAA;gBAC9D,IAAI,QAAQ,KAAK,OAAO;oBAAE,WAAW,EAAE,CAAA;gBACvC,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,EAAE,OAAO,CAAC,CAAA;gBAEtC,IAAI,CAAC,eAAe,EAAE,CAAA;gBAEtB,uBAAuB;gBACvB,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAA;gBAC5D,MAAM,cAAc,GAAG,IAAI,GAAG,EAAmB,CAAA;gBACjD,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;oBACnB,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,qBAAqB,EAAE,CAAC,CAAA;gBAC3D,CAAC,CAAC,CAAA;gBAEF,6BAA6B;gBAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;gBAEpB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE;oBAC5B,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAA;oBACnE,IAAI,SAAS,GAAuB,IAAI,CAAA;oBAExC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;wBAC1B,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;wBACzC,IAAI,CAAC,KAAK;4BAAE,OAAM;wBAElB,MAAM,IAAI,GAAG,IAAI,CAAC,qBAAqB,EAAE,CAAA;wBACzC,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;wBACjC,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAA;wBAE/B,MAAM,EAAE,GAAG,IAAmB,CAAA;wBAE9B,IAAI,IAAI,CAAC,EAAE,KAAK,cAAc,EAAE,CAAC;4BAC/B,iCAAiC;4BACjC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAA;4BACvC,SAAS,GAAG,EAAE,CAAA;wBAChB,CAAC;6BAAM,CAAC;4BACN,8BAA8B;4BAC9B,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;gCAAE,OAAM;4BAEhC,qBAAqB;4BACrB,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,aAAa,EAAE,OAAO,EAAE,KAAK,CAAA;4BAClD,EAAE,CAAC,KAAK,CAAC,UAAU,GAAG,MAAM,CAAA;4BAE5B,qBAAqB,CAAC,GAAG,EAAE;gCACzB,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;gCAC/B,EAAE,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAA;gCACvB,EAAE,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,CAAA;gCAExB,EAAE,CAAC,gBAAgB,CACjB,eAAe,EACf,GAAG,EAAE;oCACH,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,aAAa,CAAC,CAAA;gCACpC,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAA;4BACH,CAAC,CAAC,CAAA;wBACJ,CAAC;oBACH,CAAC,CAAC,CAAA;oBAEF,gDAAgD;oBAChD,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;oBACtC,MAAM,iBAAiB,GAAG,GAAG,EAAE;wBAC7B,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,WAAW,EAAE;4BAC3B,MAAM,EAAE;gCACN,OAAO,EAAE,IAAI,CAAC,KAAK;gCACnB,QAAQ;gCACR,OAAO,EAAE,cAAc;6BACxB;yBACF,CAAC,CACH,CAAA;oBACH,CAAC,CAAA;oBAED,IAAI,SAAS,EAAE,CAAC;wBACd,UAAU,CAAC,GAAG,EAAE;4BACd,CAAC;4BAAC,SAAyB,CAAC,SAAS,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAClE;4BAAC,SAAyB,CAAC,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,CACxD;4BAAC,SAAyB,CAAC,gBAAgB,CAC1C,cAAc,EACd,GAAG,EAAE;gCACH,CAAC;gCAAC,SAAyB,CAAC,SAAS,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;gCAC5D,iBAAiB,EAAE,CAAA;4BACrB,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAA;wBACH,CAAC,EAAE,GAAG,CAAC,CAAA;oBACT,CAAC;yBAAM,CAAC;wBACN,iBAAiB,EAAE,CAAA;oBACrB,CAAC;gBACH,CAAC,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;YAEF,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAQ,EAAE,EAAE;gBACvD,IAAI,CAAC,mBAAmB,EAAE,CAAA;gBAC1B,MAAM,MAAM,GAAI,CAAC,CAAC,MAAsB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;gBAC1D,IAAI,MAAM;oBAAE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;gBAC/C,IAAI,CAAC,eAAe,EAAE,CAAA;YACxB,CAAC,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IAEO,mBAAmB;QACzB,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,cAAc,IAAI,CAAC,aAAa,IAAI,CAAC,CAAA;YAC9E,IAAI,EAAE,EAAE,CAAC;gBACP,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;YAClD,CAAC;QACH,CAAC;QACD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAA;QACzB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;IACvB,CAAC;IAEO,eAAe;QACrB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAA;QACtB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAA;QACzB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;IACvB,CAAC;IAED,MAAM;QACJ,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAA;QAEhC,OAAO,IAAI,CAAA;QACP,IAAI,CAAC,SAAS;YACd,CAAC,CAAC,UAAU,CACR,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,EAC5C,IAAI,CAAA;;+CAE+B,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,kBAAkB;;;4BAGvE,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,IAAI,cAAc;;aAEhE,CACF;YACH,CAAC,CAAC,OAAO;QACT,MAAM,CACN,MAAM,EACN,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EACjB,KAAK,CAAC,EAAE,CAAC,IAAI,CAAA;0CACqB,KAAK,CAAC,EAAE;oCACd,KAAK,CAAC,EAAE;yBACnB,KAAK,CAAC,SAAS;;;wBAGhB,KAAK,CAAC,IAAI;oCACE,KAAK,CAAC,WAAW;;;;;uBAK9B,CAAC,CAAC,EAAE;YACX,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;YACrB,CAAC,CAAC,cAAc,EAAE,CAAA;QACpB,CAAC;;;;cAID,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACzC,CAAC,CAAC,IAAI,CAAA,oCAAoC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,kBAAkB;YAC9F,CAAC,CAAC,IAAI,CAAA,4BAA4B,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,yBAAyB;;SAE/F,CACF;KACF,CAAA;IACH,CAAC;IAED,OAAO,CAAC,OAA6B;QACnC,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5D,MAAM,WAAW,GAAG,CAAC,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,CAAC,CAAA;YAE7E,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACjC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,cAAc,EAAE,IAAI,CAAC,CAAA;gBAChE,IAAI,CAAC,IAAI;oBAAE,SAAQ;gBAEnB,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAA;gBAC7E,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;gBAC7B,IAAI,CAAC,gBAAgB,CACnB,cAAc,EACd,GAAG,EAAE;oBACH,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;gBAClC,CAAC,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,CACf,CAAA;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS,CAAC,KAAK;QACb,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,YAAY,EAAE;YAC5B,MAAM,EAAE,KAAK;SACd,CAAC,CACH,CAAA;IACH,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,OAAO;QAC1B,MAAM,MAAM,CAAC,MAAM,CAAC;YAClB,QAAQ,EAAE,GAAG,CAAA;;qCAEkB,OAAO;;OAErC;SACF,CAAC,CAAA;QAEF,IAAI,CAAC,gBAAgB,EAAE,CAAA;IACzB,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAO;QACvB,MAAM,MAAM,CAAC,MAAM,CAAC;YAClB,QAAQ,EAAE,GAAG,CAAA;;;wBAGK,OAAO;;;;;;OAMxB;SACF,CAAC,CAAA;QAEF,IAAI,CAAC,gBAAgB,EAAE,CAAA;IACzB,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,mBAAmB,CAAC,CAAC,CAAA;IAC1D,CAAC;;AA7T0B;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;;6CAAmB;AAClB;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;;gDAAsB;AACrB;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;;6CAAmB;AACjB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;4CAAe;AACb;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;;gDAA4B;AACF;IAArD,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC;;iDAAoB;AAClB;IAAtD,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC;;kDAA6B;AACxD;IAA1B,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;;iDAA0B;AAlPzC,aAAa;IADzB,aAAa,CAAC,iBAAiB,CAAC;GACpB,aAAa,CAyiBzB","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport gql from 'graphql-tag'\nimport { css, html, LitElement, PropertyValues, nothing } from 'lit'\nimport { customElement, property, state, query } from 'lit/decorators.js'\nimport { repeat } from 'lit/directives/repeat.js'\n\nimport { client } from '@operato/graphql'\nimport { i18next } from '@operato/i18n'\n\nimport { privileged } from '@things-factory/auth-base/dist-client/index.js'\n\n@customElement('board-tile-list')\nexport class BoardTileList extends LitElement {\n static styles = [\n css`\n :host {\n overflow: auto;\n padding: var(--popup-content-padding);\n display: grid;\n background-color: var(--md-sys-color-background);\n\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n grid-auto-rows: var(--card-list-rows-height);\n grid-gap: 20px;\n }\n\n [card] {\n position: relative;\n align-items: center;\n overflow: hidden;\n }\n\n [card][create] {\n overflow: visible;\n background-color: initial;\n }\n\n [card][import-card] > a {\n display: flex;\n align-items: center;\n justify-content: center;\n height: calc(100% - 25px);\n border: 1px dashed var(--md-sys-color-outline-variant, #b8c2cc);\n border-radius: var(--card-list-border-radius, 8px);\n text-decoration: none;\n color: var(--md-sys-color-on-secondary-container, #555);\n background: var(--md-sys-color-surface-container, #fff);\n box-sizing: border-box;\n }\n [card][import-card] > a:hover {\n border-color: var(--md-sys-color-primary, #2a64d8);\n color: var(--md-sys-color-primary, #2a64d8);\n background: var(--md-sys-color-primary-container, #eaf2ff);\n }\n [card][import-card] md-icon {\n font-size: 48px;\n --md-icon-size: 48px;\n }\n\n [card] > a {\n display: flex;\n align-items: center;\n justify-content: center;\n clip-path: border-box;\n padding: var(--spacing-large);\n box-sizing: border-box;\n }\n\n [card]:hover {\n cursor: pointer;\n }\n\n /* 데스크탑 (hover 가능 + 정밀 포인터): 액션 아이콘 fade-in.\n * favored 별은 *상태 표시* 라 호버 무관하게 보임 — 어떤 보드가 즐겨찾기인지\n * 한눈에. unfavored 별 + info 만 호버 시 노출.\n * 모바일/터치 환경에서는 hover 가 없으므로 이 블록이 미적용 → 기본 동작\n * (별/메뉴 항상 노출) 그대로 유지. */\n @media (hover: hover) and (pointer: fine) {\n md-icon[iconBtn]:not([favored]) {\n opacity: 0;\n transition: opacity 0.2s ease;\n }\n\n [card]:hover md-icon[iconBtn] {\n opacity: 1;\n }\n }\n\n [name] {\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n margin-top: var(--spacing-small);\n margin-left: var(--spacing-large);\n /* 좌측 inset (margin-left) + 우측 액션 영역 (45px) + 우측 inset = 양쪽 대칭 */\n width: calc(100% - 45px - var(--spacing-large) * 2);\n color: var(--md-sys-color-on-background);\n font-weight: bolder;\n font-size: var(--fontsize-small);\n }\n\n img {\n max-width: 100%;\n max-height: 100%;\n width: auto;\n height: auto;\n object-fit: contain;\n border-radius: var(--card-list-thumbnail-radius);\n }\n\n md-icon[iconBtn] {\n float: right;\n margin-top: -20px;\n margin-left: 2px;\n color: var(--board-list-star-color);\n font-size: 1.4em;\n }\n /* info 가 render 순서상 첫째 = float right 시 가장 우측 — 카드 우측 inset 적용 */\n md-icon[iconBtn][info] {\n color: var(--md-sys-color-primary);\n margin-right: var(--spacing-large);\n }\n\n md-icon[iconBtn][favored],\n md-icon[info]:hover {\n color: var(--board-list-star-active-color);\n }\n\n a {\n display: block;\n border-radius: var(--card-list-border-radius);\n border: var(--border-dim-color);\n box-sizing: border-box;\n color: var(--card-list-color);\n background-color: var(--card-list-background-color);\n margin: 0px;\n height: calc(100% - 25px);\n }\n\n [draggable='true'] {\n cursor: grab;\n transition: opacity 0.2s ease, transform 0.2s ease;\n }\n\n [card].dragging {\n opacity: 0.3;\n transform: scale(0.95);\n }\n\n [card].drop-before {\n border-left: 3px solid var(--md-sys-color-primary);\n }\n\n [card].drop-after {\n border-right: 3px solid var(--md-sys-color-primary);\n }\n\n [card].flip-moving {\n transition: transform 1s cubic-bezier(0.25, 0.1, 0.25, 1);\n }\n\n @keyframes drop-land {\n 0% {\n opacity: 0;\n transform: scale(0.9);\n }\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n }\n\n [card].flip-dropped-hidden {\n opacity: 0;\n }\n\n [card].flip-dropped {\n animation: drop-land 0.5s cubic-bezier(0.22, 0.6, 0.36, 1);\n }\n\n @keyframes highlight-sweep {\n 0% {\n background: linear-gradient(90deg, var(--md-sys-color-primary-container) 0%, transparent 0%);\n box-shadow: 0 0 8px 2px var(--md-sys-color-primary);\n }\n 50% {\n background: linear-gradient(90deg, transparent 0%, var(--md-sys-color-primary-container) 50%, transparent 100%);\n box-shadow: 0 0 12px 3px var(--md-sys-color-primary);\n }\n 100% {\n background: transparent;\n box-shadow: none;\n }\n }\n\n @keyframes border-pulse {\n 0%,\n 100% {\n outline: 2px solid transparent;\n }\n 25%,\n 75% {\n outline: 2px solid var(--md-sys-color-primary);\n }\n }\n\n @keyframes subtle-bounce {\n 0% {\n transform: scale(1);\n }\n 30% {\n transform: scale(1.03);\n }\n 100% {\n transform: scale(1);\n }\n }\n\n @keyframes surface-flash {\n 0% {\n background-color: var(--md-sys-color-primary-container);\n }\n 100% {\n background-color: transparent;\n }\n }\n\n [card].anim-sweep {\n animation: highlight-sweep 1.8s ease;\n border-radius: 4px;\n }\n\n [card].anim-pulse {\n animation: border-pulse 1.2s ease;\n }\n\n [card].anim-bounce {\n animation: subtle-bounce 0.8s ease;\n }\n\n [card].anim-flash {\n animation: surface-flash 1.5s ease-out;\n }\n\n `\n ]\n\n @property({ type: Array }) boards: any[] = []\n @property({ type: Array }) favorites: any[] = []\n @property({ type: Array }) groups: any[] = []\n @property({ type: String }) group?: string\n @property({ type: Boolean }) creatable?: boolean = false\n @property({ type: String, attribute: 'search-text' }) searchText?: string\n @property({ type: Boolean, attribute: 'reorderable' }) reorderable: boolean = false\n @property({ type: Array }) updatedIds: string[] = []\n\n private _draggedId: string | null = null\n private _dropTargetId: string | null = null\n private _dropSide: 'before' | 'after' | null = null\n\n connectedCallback() {\n super.connectedCallback()\n\n if (this.reorderable) {\n this.renderRoot.addEventListener('dragstart', (e: Event) => {\n const target = (e.target as HTMLElement).closest('[card]') as HTMLElement | null\n if (!target?.id) return\n\n this._draggedId = target.id\n target.classList.add('dragging')\n ;(e as DragEvent).dataTransfer!.effectAllowed = 'move'\n ;(e as DragEvent).dataTransfer?.setData('text/plain', target.id)\n })\n\n this.renderRoot.addEventListener('dragover', (e: Event) => {\n e.preventDefault()\n ;(e as DragEvent).dataTransfer!.dropEffect = 'move'\n\n const target = (e.target as HTMLElement).closest('[card]') as HTMLElement | null\n if (!target?.id || target.id === this._draggedId) return\n\n const targetRect = target.getBoundingClientRect()\n const mousePos = (e as DragEvent).clientX - targetRect.left\n const side = mousePos < targetRect.width / 2 ? 'before' : 'after'\n\n if (this._dropTargetId !== target.id || this._dropSide !== side) {\n this._clearDropIndicator()\n this._dropTargetId = target.id\n this._dropSide = side\n target.classList.add(side === 'before' ? 'drop-before' : 'drop-after')\n }\n })\n\n this.renderRoot.addEventListener('dragleave', (e: Event) => {\n const target = (e.target as HTMLElement).closest('[card]') as HTMLElement | null\n if (target?.id === this._dropTargetId) {\n const related = (e as DragEvent).relatedTarget as HTMLElement | null\n if (!related || !target.contains(related)) {\n this._clearDropIndicator()\n }\n }\n })\n\n this.renderRoot.addEventListener('drop', (e: Event) => {\n e.preventDefault()\n\n // drop 이벤트에서 직접 타겟과 방향을 계산 (dragleave가 먼저 발생해 상태를 지울 수 있으므로)\n const dropTarget = (e.target as HTMLElement).closest('[card]') as HTMLElement | null\n let dropTargetId = this._dropTargetId\n let dropSide = this._dropSide\n\n if (dropTarget?.id && dropTarget.id !== this._draggedId) {\n dropTargetId = dropTarget.id\n const rect = dropTarget.getBoundingClientRect()\n dropSide = (e as DragEvent).clientX - rect.left < rect.width / 2 ? 'before' : 'after'\n }\n\n this._clearDropIndicator()\n\n const draggedEl = this._draggedId ? this.renderRoot.querySelector(`[card][id=\"${this._draggedId}\"]`) : null\n if (draggedEl) {\n draggedEl.classList.remove('dragging')\n }\n\n if (!this._draggedId || !dropTargetId || this._draggedId === dropTargetId) {\n this._resetDragState()\n return\n }\n\n // 배열 재정렬\n const boards = [...this.boards]\n const draggedIndex = boards.findIndex(b => b.id === this._draggedId)\n if (draggedIndex === -1) {\n this._resetDragState()\n return\n }\n\n const draggedBoardId = this._draggedId\n const [dragged] = boards.splice(draggedIndex, 1)\n let targetIndex = boards.findIndex(b => b.id === dropTargetId)\n if (dropSide === 'after') targetIndex++\n boards.splice(targetIndex, 0, dragged)\n\n this._resetDragState()\n\n // FLIP 애니메이션: 이전 위치 기록\n const cards = this.renderRoot.querySelectorAll('[card][id]')\n const firstPositions = new Map<string, DOMRect>()\n cards.forEach(card => {\n firstPositions.set(card.id, card.getBoundingClientRect())\n })\n\n // optimistic update → Lit 렌더\n this.boards = boards\n\n this.updateComplete.then(() => {\n const updatedCards = this.renderRoot.querySelectorAll('[card][id]')\n let droppedEl: HTMLElement | null = null\n\n updatedCards.forEach(card => {\n const first = firstPositions.get(card.id)\n if (!first) return\n\n const last = card.getBoundingClientRect()\n const dx = first.left - last.left\n const dy = first.top - last.top\n\n const el = card as HTMLElement\n\n if (card.id === draggedBoardId) {\n // 드래그한 카드: 슬라이딩 완료 후 착지하도록 일단 숨김\n el.classList.add('flip-dropped-hidden')\n droppedEl = el\n } else {\n // 밀려나는 카드: 이전 위치에서 새 위치로 슬라이딩\n if (dx === 0 && dy === 0) return\n\n // Invert: 이전 위치로 되돌림\n el.style.transform = `translate(${dx}px, ${dy}px)`\n el.style.transition = 'none'\n\n requestAnimationFrame(() => {\n el.classList.add('flip-moving')\n el.style.transform = ''\n el.style.transition = ''\n\n el.addEventListener(\n 'transitionend',\n () => {\n el.classList.remove('flip-moving')\n },\n { once: true }\n )\n })\n }\n })\n\n // 밀려나는 카드 슬라이딩 완료 후 드래그한 카드 착지 → 착지 완료 후 이벤트 발송\n const boardIds = boards.map(b => b.id)\n const dispatchReordered = () => {\n this.dispatchEvent(\n new CustomEvent('reordered', {\n detail: {\n groupId: this.group,\n boardIds,\n movedId: draggedBoardId\n }\n })\n )\n }\n\n if (droppedEl) {\n setTimeout(() => {\n ;(droppedEl as HTMLElement).classList.remove('flip-dropped-hidden')\n ;(droppedEl as HTMLElement).classList.add('flip-dropped')\n ;(droppedEl as HTMLElement).addEventListener(\n 'animationend',\n () => {\n ;(droppedEl as HTMLElement).classList.remove('flip-dropped')\n dispatchReordered()\n },\n { once: true }\n )\n }, 500)\n } else {\n dispatchReordered()\n }\n })\n })\n\n this.renderRoot.addEventListener('dragend', (e: Event) => {\n this._clearDropIndicator()\n const target = (e.target as HTMLElement).closest('[card]')\n if (target) target.classList.remove('dragging')\n this._resetDragState()\n })\n }\n }\n\n private _clearDropIndicator() {\n if (this._dropTargetId) {\n const el = this.renderRoot.querySelector(`[card][id=\"${this._dropTargetId}\"]`)\n if (el) {\n el.classList.remove('drop-before', 'drop-after')\n }\n }\n this._dropTargetId = null\n this._dropSide = null\n }\n\n private _resetDragState() {\n this._draggedId = null\n this._dropTargetId = null\n this._dropSide = null\n }\n\n render() {\n const boards = this.boards || []\n\n return html`\n ${this.creatable\n ? privileged(\n { privilege: 'mutation', category: 'board' },\n html`\n <div card import-card>\n <a href=\"board-create\" title=${i18next.t('text.create board') || 'Create New Board'}>\n <md-icon>add_circle_outline</md-icon>\n </a>\n <div name>${i18next.t('label.create board') || 'Create Board'}</div>\n </div>\n `\n )\n : nothing}\n ${repeat(\n boards,\n board => board.id,\n board => html`\n <div card draggable=\"true\" id=${board.id}>\n <a href=\"board-viewer/${board.id}\">\n <img src=${board.thumbnail} />\n </a>\n\n <div name>${board.name}</div>\n <!-- <div description>${board.description}</div> -->\n\n <md-icon\n iconBtn\n info\n @click=${e => {\n this.infoBoard(board)\n e.preventDefault()\n }}\n >info</md-icon\n >\n\n ${(this.favorites || []).includes(board.id)\n ? html` <md-icon iconBtn favored @click=${e => this.removeFavorite(board.id)}>star</md-icon> `\n : html` <md-icon iconBtn @click=${e => this.addFavorite(board.id)}>star_border</md-icon> `}\n </div>\n `\n )}\n `\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('updatedIds') && this.updatedIds.length > 0) {\n const animClasses = ['anim-sweep', 'anim-pulse', 'anim-bounce', 'anim-flash']\n\n for (const id of this.updatedIds) {\n const card = this.renderRoot.querySelector(`[card][id=\"${id}\"]`)\n if (!card) continue\n\n const animClass = animClasses[Math.floor(Math.random() * animClasses.length)]\n card.classList.add(animClass)\n card.addEventListener(\n 'animationend',\n () => {\n card.classList.remove(animClass)\n },\n { once: true }\n )\n }\n }\n }\n\n infoBoard(board) {\n this.dispatchEvent(\n new CustomEvent('info-board', {\n detail: board\n })\n )\n }\n\n async removeFavorite(boardId) {\n await client.mutate({\n mutation: gql`\n mutation {\n deleteFavorite(routing: \"${boardId}\")\n }\n `\n })\n\n this.refreshFavorites()\n }\n\n async addFavorite(boardId) {\n await client.mutate({\n mutation: gql`\n mutation {\n createFavorite(favorite: {\n routing: \"${boardId}\"\n }) {\n id\n routing\n }\n }\n `\n })\n\n this.refreshFavorites()\n }\n\n async refreshFavorites() {\n this.dispatchEvent(new CustomEvent('refresh-favorites'))\n }\n}\n"]}
@@ -27,7 +27,10 @@ body {
27
27
  --card-list-rows-height: 180px;
28
28
  --card-list-color: var(--md-sys-color-on-surface);
29
29
  --card-list-background-color: var(--md-sys-color-surface-container-lowest);
30
- --card-list-border-radius: var(--border-radius);
30
+ /* Material 3 shape token — data-grist 카드와 동일 톤 (corner-medium 외곽 +
31
+ * corner-small 동심 안쪽). nested rounded containers 의 자연 계층. */
32
+ --card-list-border-radius: var(--md-sys-shape-corner-medium);
33
+ --card-list-thumbnail-radius: var(--md-sys-shape-corner-small);
31
34
  --card-list-flip-transform: rotateX(180deg);
32
35
  --card-list-create-border: 1px dashed var(--md-sys-color-primary);
33
36
  --card-list-create-border-radius: var(--border-radius);