@madeinbruno/atelier 0.6.1 → 0.7.1

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.
package/README.md CHANGED
@@ -59,7 +59,20 @@ export default function Footer() {
59
59
  />
60
60
  ```
61
61
 
62
- 설정 화면에서 미리 보기용으로 `CareLabel`만 따로 쓸 수도 있어요 (`.mib-tag__care` 스타일 포함). 관심사가 아직 보이는 중인지는 `activeInterest(interest)`, 끊은 지 며칠째인지는 `quitDay(quit)`로 알 수 있어요. 고를 수 있는 아이콘은 `CARE_ICONS`에 있어요 (음악, 영화, 책, 사진, 게임, 코드, 커피, 식물, 운동, 글, 마음).
62
+ **상태는 한 곳에서 바꿔요.** 택 상태는 `apps/atelier`(atelier.madeinbruno.com)에서 주인이 바꾸고, 모든 서비스는 `fetchCareState()`로 같은 상태를 받아 그려요.
63
+
64
+ ```tsx
65
+ import { Tag, fetchCareState } from '@madeinbruno/atelier';
66
+
67
+ export default async function Footer() {
68
+ const care = await fetchCareState(); // 서버에서. Next.js에서는 1분 캐시
69
+ return <Tag service="hangoutwithme" care={care} />;
70
+ }
71
+ ```
72
+
73
+ - 받아 오지 못하면(3초 안에 응답이 없거나 에러) 기본 상태로 그려서 페이지가 깨지지 않아요.
74
+ - 주소는 `CARE_STATE_URL`(기본 `https://atelier.madeinbruno.com/api/care`). 다른 곳에서 받으려면 `fetchCareState(url)`.
75
+ - 설정 화면에서 미리 보기용으로 `CareLabel`만 따로 쓸 수도 있어요 (`.mib-tag__care` 스타일 포함). 관심사가 아직 보이는 중인지는 `activeInterest(interest)`, 끊은 지 며칠째인지는 `quitDay(quit)`로 알 수 있어요. 고를 수 있는 아이콘은 `CARE_ICONS`에 있어요 (음악, 영화, 책, 사진, 게임, 코드, 커피, 식물, 운동, 글, 마음).
63
76
 
64
77
  `madeinbruno` 글씨는 [Banquise](https://gitlab.com/bonjour-monde/fonderie/banquise-typeface)(Bonjour Monde, SIL Open Font License 1.1)로 쓴 글자를 SVG 그림으로 옮긴 거예요. 이 한 단어에만 쓰는 폰트라 폰트 파일을 싣지 않아요 (15KB → 1KB 미만, 글씨가 늦게 바뀌는 깜빡임도 없음).
65
78
 
package/dist/index.d.ts CHANGED
@@ -122,4 +122,17 @@ type TagProps = {
122
122
  };
123
123
  declare function Tag({ service, email, href, since, eyebrow, message, background, stitch, care, className, }: TagProps): react.JSX.Element;
124
124
 
125
- export { CARE_ICONS, type CareIcon, CareLabel, type CareState, DEFAULT_CARE_STATE, INTEREST_DAYS, Tag, type TagProps, activeInterest, isCareIcon, quitDay, todayInKorea };
125
+ /** 택 상태를 바꾸는 곳(apps/atelier)의 공개 주소 */
126
+ declare const CARE_STATE_URL = "https://atelier.madeinbruno.com/api/care";
127
+ /** 받아 온 값에서 지금 쓰는 항목만, 모양이 맞는 것만 꺼낸다 */
128
+ declare function normalizeCareState(raw: unknown): Required<CareState>;
129
+ /**
130
+ * 택 세탁 표시의 지금 상태를 atelier에서 받아 온다. 서버(예: Next.js 서버 컴포넌트)에서 부른다.
131
+ * Next.js에서는 1분 동안 캐시한다. 못 받으면(3초 안에 응답이 없거나 에러) 기본 상태로 그려서 페이지가 깨지지 않는다.
132
+ *
133
+ * const care = await fetchCareState();
134
+ * <Tag service="..." care={care} />
135
+ */
136
+ declare function fetchCareState(url?: string): Promise<Required<CareState>>;
137
+
138
+ export { CARE_ICONS, CARE_STATE_URL, type CareIcon, CareLabel, type CareState, DEFAULT_CARE_STATE, INTEREST_DAYS, Tag, type TagProps, activeInterest, fetchCareState, isCareIcon, normalizeCareState, quitDay, todayInKorea };
package/dist/index.js CHANGED
@@ -199,14 +199,41 @@ function Tag({
199
199
  ] }) }) })
200
200
  ] }) });
201
201
  }
202
+
203
+ // src/fetchCareState.ts
204
+ var CARE_STATE_URL = "https://atelier.madeinbruno.com/api/care";
205
+ function normalizeCareState(raw) {
206
+ const v = raw ?? {};
207
+ const i = v.interest;
208
+ const q = v.quit;
209
+ return {
210
+ heat: v.heat === 1 || v.heat === 3 ? v.heat : 2,
211
+ interest: i && typeof i.text === "string" && i.text && typeof i.since === "string" ? { text: i.text, since: i.since, icon: isCareIcon(i.icon) ? i.icon : null } : null,
212
+ quit: q && typeof q.text === "string" && q.text && typeof q.since === "string" ? { text: q.text, since: q.since } : null,
213
+ wet: v.wet === true
214
+ };
215
+ }
216
+ async function fetchCareState(url = CARE_STATE_URL) {
217
+ try {
218
+ const init = { next: { revalidate: 60 }, signal: AbortSignal.timeout(3e3) };
219
+ const res = await fetch(url, init);
220
+ if (!res.ok) return DEFAULT_CARE_STATE;
221
+ return normalizeCareState(await res.json());
222
+ } catch {
223
+ return DEFAULT_CARE_STATE;
224
+ }
225
+ }
202
226
  export {
203
227
  CARE_ICONS,
228
+ CARE_STATE_URL,
204
229
  CareLabel,
205
230
  DEFAULT_CARE_STATE,
206
231
  INTEREST_DAYS,
207
232
  Tag,
208
233
  activeInterest,
234
+ fetchCareState,
209
235
  isCareIcon,
236
+ normalizeCareState,
210
237
  quitDay,
211
238
  todayInKorea
212
239
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@madeinbruno/atelier",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "description": "madeinbruno.com 서비스들이 같이 쓰는 공용 컴포넌트 (옷 만드는 작업실 컨셉: 택, 라벨, 도장…)",
5
5
  "license": "MIT",
6
6
  "author": "codingbotPark <pbk575@gmail.com>",
package/styles.css CHANGED
@@ -193,27 +193,34 @@
193
193
  }
194
194
 
195
195
  /* 툴팁: 기호 위에 작은 글씨가 뜬다 (CSS만, 스크립트 없음).
196
- 세탁 표시 줄이 택 왼쪽에 붙어 있으므로 기호 왼쪽 끝에서 오른쪽으로 펼쳐 택·화면 밖으로 나가지 않게 한다. */
197
- .mib-tag__care-item {
196
+ 기호가 아니라 세탁 표시 줄(.mib-tag__care, 택 안쪽 폭) 기준으로 띄운다: 줄 왼쪽 끝에서 시작하고
197
+ 폭은 줄을 넘지 않으며, 길면 잘라내지 않고 줄을 바꿔 끝까지 보여 준다. 그래서 택 밖으로 나가지 않는다. */
198
+ .mib-tag__care {
198
199
  position: relative;
200
+ }
201
+
202
+ .mib-tag__care-item {
199
203
  display: flex;
200
204
  }
201
205
 
202
206
  .mib-tag__care-item[data-tip]::after {
203
207
  content: attr(data-tip);
204
208
  position: absolute;
205
- bottom: calc(100% + 8px);
209
+ bottom: calc(100% + 6px);
206
210
  left: 0;
211
+ width: max-content;
212
+ max-width: 100%;
213
+ box-sizing: border-box;
207
214
  padding: 4px 8px;
208
215
  border-radius: 4px;
209
216
  background: var(--mib-ink);
210
217
  color: #fff;
211
218
  font-size: 11px;
212
- line-height: 1.3;
213
- white-space: nowrap;
214
- max-width: 240px;
215
- overflow: hidden;
216
- text-overflow: ellipsis;
219
+ line-height: 1.4;
220
+ white-space: normal;
221
+ /* 한국어는 단어 중간이 아니라 띄어쓰기에서 줄을 바꾼다. 아주 긴 한 단어만 어쩔 수 없이 자른다 */
222
+ word-break: keep-all;
223
+ overflow-wrap: anywhere;
217
224
  pointer-events: none;
218
225
  opacity: 0;
219
226
  transform: translateY(2px);