style.scss 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. .rank-config {
  2. display: flex;
  3. flex-direction: column;
  4. // ── 목록 패널 ────────────────────────────────────
  5. &__list-panel {
  6. display: flex;
  7. flex-direction: column;
  8. gap: 0;
  9. }
  10. // ── 30/70 레이아웃 ────────────────────────────────
  11. &__layout {
  12. display: grid;
  13. grid-template-columns: minmax(0, 500px) auto 1fr;
  14. gap: 24px;
  15. align-items: start;
  16. }
  17. // ── 좌측 패널 (미리보기) ─────────────────────────
  18. &__preview-panel {
  19. position: sticky;
  20. top: 16px;
  21. display: flex;
  22. flex-direction: column;
  23. gap: 16px;
  24. max-height: calc(100vh - 48px);
  25. overflow-y: auto;
  26. }
  27. // ── 우측 패널 (폼) ───────────────────────────────
  28. &__form-panel {
  29. display: flex;
  30. flex-direction: column;
  31. gap: 0;
  32. }
  33. // ── 섹션 ─────────────────────────────────────────
  34. &__section {
  35. display: grid;
  36. grid-template-columns: 140px 1fr;
  37. gap: 24px;
  38. padding: 24px 0;
  39. border-bottom: 1px solid hsl(var(--border));
  40. &:first-of-type {
  41. padding-top: 0;
  42. }
  43. }
  44. &__section-title {
  45. font-size: 0.875rem;
  46. font-weight: 600;
  47. color: hsl(var(--foreground));
  48. padding-top: 2px;
  49. margin: 0;
  50. }
  51. &__section-body {
  52. display: flex;
  53. flex-direction: column;
  54. gap: 17px;
  55. max-width: 520px;
  56. }
  57. // ── 위젯 미리보기 ────────────────────────────────
  58. &__widget {
  59. border: 1px solid hsl(var(--border));
  60. border-radius: var(--radius);
  61. overflow: hidden;
  62. }
  63. &__widget-label {
  64. padding: 8px 14px;
  65. font-size: 0.8125rem;
  66. font-weight: 500;
  67. color: hsl(var(--muted));
  68. background: #0e0e1a;
  69. }
  70. &__widget-body {
  71. padding: 16px;
  72. &--basic {
  73. background: #1a1a2e;
  74. }
  75. &--dark {
  76. background: #0a0a14;
  77. }
  78. &--minimal {
  79. background: #222;
  80. }
  81. }
  82. // ── fieldset (미리보기 패널용) ────────────────────
  83. &__fieldset {
  84. border: 1px solid hsl(var(--border));
  85. border-radius: var(--radius);
  86. padding: 16px 20px 20px;
  87. margin: 0;
  88. }
  89. &__legend {
  90. font-size: 1rem;
  91. font-weight: 600;
  92. color: hsl(var(--foreground));
  93. padding: 0 8px;
  94. margin-left: -4px;
  95. }
  96. // ── 미리보기 테스트 폼 ───────────────────────────
  97. &__preview-form {
  98. display: flex;
  99. flex-direction: column;
  100. gap: 12px;
  101. }
  102. &__preview-actions {
  103. display: flex;
  104. gap: 8px;
  105. margin-top: 4px;
  106. }
  107. &__preview-btn {
  108. flex: 1;
  109. justify-content: center;
  110. }
  111. &__field-hint {
  112. margin: 0;
  113. font-size: 0.8125rem;
  114. color: hsl(var(--muted-foreground));
  115. }
  116. // ── 툴바 ─────────────────────────────────────────
  117. &__toolbar {
  118. display: flex;
  119. align-items: center;
  120. justify-content: space-between;
  121. gap: 8px;
  122. margin-bottom: 12px;
  123. flex-wrap: wrap;
  124. }
  125. &__toolbar-left {
  126. display: flex;
  127. align-items: baseline;
  128. gap: 6px;
  129. }
  130. &__toolbar-right {
  131. display: flex;
  132. align-items: center;
  133. gap: 6px;
  134. flex-wrap: wrap;
  135. }
  136. &__count {
  137. font-size: 0.8125rem;
  138. color: hsl(var(--muted-foreground));
  139. }
  140. &__per-page {
  141. padding: 9px 10px;
  142. border: 1px solid hsl(var(--border));
  143. border-radius: calc(var(--radius) - 2px);
  144. background: hsl(var(--background));
  145. color: hsl(var(--foreground));
  146. font-size: 0.875rem;
  147. cursor: pointer;
  148. }
  149. // ── 버튼 ─────────────────────────────────────────
  150. &__btn {
  151. display: inline-flex;
  152. align-items: center;
  153. gap: 6px;
  154. padding: 8px 16px;
  155. border: 1px solid hsl(var(--border));
  156. border-radius: calc(var(--radius) - 2px);
  157. background: hsl(var(--background));
  158. color: hsl(var(--foreground));
  159. font-size: 0.875rem;
  160. font-weight: 500;
  161. cursor: pointer;
  162. white-space: nowrap;
  163. transition: background-color 0.15s, color 0.15s;
  164. justify-content: center;
  165. &:not([class*="--"]):hover:not(:disabled) {
  166. background: hsl(var(--accent));
  167. color: hsl(var(--accent-foreground));
  168. }
  169. &:disabled {
  170. opacity: 0.5;
  171. cursor: not-allowed;
  172. }
  173. &--sm {
  174. padding: 4px 10px;
  175. font-size: 0.75rem;
  176. }
  177. &--primary {
  178. background: hsl(var(--primary));
  179. color: hsl(var(--primary-foreground));
  180. border-color: hsl(var(--primary));
  181. &:hover:not(:disabled) {
  182. background: hsl(var(--primary) / 0.9);
  183. color: hsl(var(--primary-foreground));
  184. }
  185. }
  186. &--danger {
  187. color: hsl(var(--destructive));
  188. border-color: hsl(var(--destructive) / 0.5);
  189. &:hover:not(:disabled) {
  190. background: hsl(var(--destructive) / 0.1);
  191. }
  192. }
  193. }
  194. // ── 테이블 ───────────────────────────────────────
  195. &__table-wrap {
  196. border: 1px solid hsl(var(--border));
  197. border-radius: var(--radius);
  198. overflow: hidden;
  199. }
  200. &__table {
  201. width: 100%;
  202. border-collapse: collapse;
  203. font-size: 0.8125rem;
  204. th, td {
  205. padding: 10px 12px;
  206. text-align: left;
  207. border-bottom: 1px solid hsl(var(--border));
  208. }
  209. th {
  210. font-weight: 500;
  211. color: hsl(var(--muted-foreground));
  212. font-size: 0.75rem;
  213. background: hsl(var(--muted) / 0.4);
  214. }
  215. tbody tr:last-child td {
  216. border-bottom: none;
  217. }
  218. tbody tr {
  219. transition: background 0.15s;
  220. }
  221. tbody tr:hover {
  222. background: hsl(var(--muted) / 0.5);
  223. }
  224. }
  225. &__th--check,
  226. &__td--check {
  227. width: 40px;
  228. text-align: center;
  229. }
  230. &__row--checked {
  231. opacity: 0.5;
  232. td {
  233. text-decoration: line-through;
  234. }
  235. }
  236. &__status-badge {
  237. display: inline-flex;
  238. align-items: center;
  239. padding: 2px 8px;
  240. border-radius: calc(var(--radius) - 2px);
  241. font-size: 0.6875rem;
  242. font-weight: 500;
  243. white-space: nowrap;
  244. &--active {
  245. background: hsl(142 71% 45% / 0.1);
  246. color: hsl(142 71% 45%);
  247. }
  248. &--inactive {
  249. background: hsl(var(--muted));
  250. color: hsl(var(--muted-foreground));
  251. }
  252. }
  253. // 활성 토글 스위치
  254. &__active-toggle {
  255. position: relative;
  256. display: inline-flex;
  257. align-items: center;
  258. width: 42px;
  259. height: 22px;
  260. padding: 2px;
  261. border: 1px solid hsl(var(--border));
  262. border-radius: 999px;
  263. background: hsl(var(--muted));
  264. cursor: pointer;
  265. transition: background 0.18s, border-color 0.18s;
  266. &-knob {
  267. width: 16px;
  268. height: 16px;
  269. border-radius: 50%;
  270. background: #fff;
  271. box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  272. transition: transform 0.18s;
  273. }
  274. &--on {
  275. background: hsl(142 71% 45%);
  276. border-color: hsl(142 71% 45%);
  277. .rank-config__active-toggle-knob {
  278. transform: translateX(20px);
  279. }
  280. }
  281. &--busy {
  282. opacity: 0.7;
  283. cursor: progress;
  284. }
  285. &:disabled {
  286. cursor: not-allowed;
  287. &:not(.rank-config__active-toggle--busy) {
  288. opacity: 0.6;
  289. }
  290. }
  291. &:not(:disabled):hover {
  292. border-color: hsl(142 71% 45%);
  293. }
  294. }
  295. &__empty {
  296. padding: 48px 16px;
  297. text-align: center;
  298. color: hsl(var(--muted-foreground));
  299. font-size: 0.875rem;
  300. }
  301. &__loading {
  302. padding: 48px 16px;
  303. text-align: center;
  304. color: hsl(var(--muted-foreground));
  305. font-size: 0.875rem;
  306. }
  307. // ── 페이징 ───────────────────────────────────────
  308. &__pagination {
  309. display: flex;
  310. align-items: center;
  311. justify-content: center;
  312. gap: 4px;
  313. margin-top: 12px;
  314. }
  315. &__page-btn {
  316. min-width: 28px;
  317. height: 28px;
  318. display: inline-flex;
  319. align-items: center;
  320. justify-content: center;
  321. border: 1px solid hsl(var(--border));
  322. border-radius: calc(var(--radius) - 2px);
  323. background: hsl(var(--background));
  324. color: hsl(var(--foreground));
  325. font-size: 0.75rem;
  326. cursor: pointer;
  327. transition: background-color 0.15s;
  328. &:hover:not(:disabled) {
  329. background: hsl(var(--accent));
  330. }
  331. &:disabled {
  332. opacity: 0.5;
  333. cursor: not-allowed;
  334. }
  335. &--active {
  336. background: hsl(var(--primary));
  337. color: hsl(var(--primary-foreground));
  338. border-color: hsl(var(--primary));
  339. }
  340. }
  341. // ── 폼 필드 ──────────────────────────────────────
  342. &__field {
  343. display: flex;
  344. flex-direction: column;
  345. gap: 6px;
  346. }
  347. &__field-label {
  348. font-size: 0.875rem;
  349. font-weight: 500;
  350. color: hsl(var(--foreground));
  351. }
  352. &__field-row {
  353. display: grid;
  354. grid-template-columns: 1fr 1fr;
  355. gap: 10px;
  356. }
  357. &__input {
  358. padding: 8px 12px;
  359. border: 1px solid hsl(var(--border));
  360. border-radius: calc(var(--radius) - 2px);
  361. background: hsl(var(--background));
  362. color: hsl(var(--foreground));
  363. font-size: 0.875rem;
  364. width: 100%;
  365. &::placeholder {
  366. color: hsl(var(--muted-foreground));
  367. }
  368. &--color-text {
  369. flex: 1;
  370. min-width: 0;
  371. font-family: monospace;
  372. }
  373. }
  374. &__select {
  375. padding: 8px 12px;
  376. border: 1px solid hsl(var(--border));
  377. border-radius: calc(var(--radius) - 2px);
  378. background: hsl(var(--background));
  379. color: hsl(var(--foreground));
  380. font-size: 0.875rem;
  381. width: 100%;
  382. cursor: pointer;
  383. }
  384. &__checkbox-label {
  385. display: inline-flex;
  386. align-items: center;
  387. gap: 8px;
  388. font-size: 0.875rem;
  389. color: hsl(var(--foreground));
  390. cursor: pointer;
  391. }
  392. // ── details 접이식 ──────────────────────────────
  393. &__details {
  394. border: 1px solid hsl(var(--border));
  395. border-radius: calc(var(--radius) - 2px);
  396. overflow: hidden;
  397. &[open] > .rank-config__details-summary {
  398. border-bottom: 1px solid hsl(var(--border));
  399. }
  400. }
  401. &__details-summary {
  402. padding: 10px 14px;
  403. font-size: 0.8125rem;
  404. font-weight: 500;
  405. color: hsl(var(--foreground));
  406. cursor: pointer;
  407. user-select: none;
  408. list-style: none;
  409. display: flex;
  410. align-items: center;
  411. gap: 6px;
  412. transition: background-color 0.15s;
  413. &:hover {
  414. background: hsl(var(--accent) / 0.5);
  415. }
  416. &::before {
  417. content: '▸';
  418. font-size: 0.75rem;
  419. transition: transform 0.15s;
  420. }
  421. &::-webkit-details-marker {
  422. display: none;
  423. }
  424. }
  425. &__details[open] > .rank-config__details-summary::before {
  426. transform: rotate(90deg);
  427. }
  428. &__details-body {
  429. display: flex;
  430. flex-direction: column;
  431. gap: 14px;
  432. padding: 14px;
  433. }
  434. // ── 색상 선택 필드 ───────────────────────────────
  435. &__color-field {
  436. display: flex;
  437. align-items: center;
  438. gap: 8px;
  439. }
  440. &__color-picker {
  441. width: 36px;
  442. height: 36px;
  443. border: 1px solid hsl(var(--border));
  444. border-radius: calc(var(--radius) - 2px);
  445. background: none;
  446. cursor: pointer;
  447. padding: 2px;
  448. flex-shrink: 0;
  449. &::-webkit-color-swatch-wrapper {
  450. padding: 0;
  451. }
  452. &::-webkit-color-swatch {
  453. border: none;
  454. border-radius: 2px;
  455. }
  456. &::-moz-color-swatch {
  457. border: none;
  458. border-radius: 2px;
  459. }
  460. }
  461. // ── 폼 하단 ──────────────────────────────────────
  462. &__form-footer {
  463. display: flex;
  464. justify-content: center;
  465. gap: 8px;
  466. padding-top: 20px;
  467. margin-top: 4px;
  468. }
  469. }
  470. // ── 순위 미리보기 ────────────────────────────────────
  471. .rank-preview {
  472. &__title {
  473. text-align: center;
  474. font-weight: 700;
  475. font-size: var(--preview-title-size, 18px);
  476. font-family: var(--preview-title-font, inherit);
  477. color: var(--preview-title-color, #fff);
  478. margin-bottom: 12px;
  479. text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.4);
  480. }
  481. &__list {
  482. display: flex;
  483. flex-direction: column;
  484. gap: 6px;
  485. }
  486. &__item {
  487. display: flex;
  488. align-items: center;
  489. gap: 10px;
  490. padding: 8px 12px;
  491. border-radius: 8px;
  492. background: rgba(255, 255, 255, 0.08);
  493. font-family: var(--row-font-family, inherit);
  494. font-size: var(--row-font-size, inherit);
  495. color: var(--row-font-color, inherit);
  496. &--1 { background: linear-gradient(135deg, rgba(255, 215, 0, 0.2), rgba(255, 215, 0, 0.05)); }
  497. &--2 { background: linear-gradient(135deg, rgba(192, 192, 192, 0.15), rgba(192, 192, 192, 0.05)); }
  498. &--3 { background: linear-gradient(135deg, rgba(205, 127, 50, 0.15), rgba(205, 127, 50, 0.05)); }
  499. }
  500. &__member-icon {
  501. width: 28px;
  502. height: 28px;
  503. border-radius: 50%;
  504. background: #444;
  505. flex-shrink: 0;
  506. border: 1px solid rgba(255, 255, 255, 0.15);
  507. }
  508. &__badge {
  509. width: 28px;
  510. height: 28px;
  511. border-radius: 50%;
  512. display: flex;
  513. align-items: center;
  514. justify-content: center;
  515. font-weight: 800;
  516. font-size: 14px;
  517. flex-shrink: 0;
  518. &--1 { background: #FFD700; color: #000; }
  519. &--2 { background: #C0C0C0; color: #000; }
  520. &--3 { background: #CD7F32; color: #fff; }
  521. &--default { background: #555; color: #fff; }
  522. }
  523. &__grade-icon {
  524. width: 18px;
  525. height: 18px;
  526. border-radius: 3px;
  527. background: linear-gradient(135deg, #6366f1, #8b5cf6);
  528. flex-shrink: 0;
  529. }
  530. &__name {
  531. flex: 1;
  532. font-weight: 600;
  533. color: #fff;
  534. font-size: 15px;
  535. overflow: hidden;
  536. text-overflow: ellipsis;
  537. white-space: nowrap;
  538. }
  539. &__meta {
  540. display: flex;
  541. align-items: center;
  542. gap: 8px;
  543. flex-shrink: 0;
  544. }
  545. &__amount {
  546. font-weight: 700;
  547. color: #FF6B35;
  548. font-size: 15px;
  549. white-space: nowrap;
  550. }
  551. &__count {
  552. font-weight: 500;
  553. color: #aaa;
  554. font-size: 13px;
  555. white-space: nowrap;
  556. }
  557. &__empty {
  558. text-align: center;
  559. color: #666;
  560. padding: 20px;
  561. }
  562. }
  563. // ── 반응형 ────────────────────────────────────────────
  564. @media (max-width: 1380px) {
  565. .rank-config {
  566. &__layout {
  567. grid-template-columns: minmax(0, 500px) auto 1fr;
  568. gap: 24px;
  569. align-items: start;
  570. }
  571. &__section {
  572. grid-template-columns: 1fr;
  573. gap: 5px;
  574. }
  575. &__section-title {
  576. margin-bottom: 9px;
  577. }
  578. }
  579. }
  580. @media (max-width: 1120px) {
  581. .rank-config {
  582. &__layout {
  583. grid-template-columns: 2fr auto 3fr;
  584. }
  585. }
  586. }
  587. @media (max-width: 768px) {
  588. .rank-config {
  589. &__layout {
  590. grid-template-columns: 1fr;
  591. }
  592. &__preview-panel {
  593. position: static;
  594. max-height: none;
  595. }
  596. &__section {
  597. grid-template-columns: 1fr;
  598. gap: 8px;
  599. }
  600. &__section-title {
  601. margin-bottom: 12px;
  602. }
  603. &__section-body {
  604. max-width: none;
  605. }
  606. &__field-row {
  607. grid-template-columns: 1fr;
  608. }
  609. &__toolbar {
  610. flex-direction: column;
  611. align-items: flex-start;
  612. }
  613. &__table-wrap {
  614. overflow-x: auto;
  615. }
  616. &__table {
  617. min-width: 700px;
  618. }
  619. }
  620. }