@operato/layout 10.2.0 → 10.3.2

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/CHANGELOG.md CHANGED
@@ -3,6 +3,35 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ### [10.3.2](https://github.com/hatiolab/operato/compare/v10.3.1...v10.3.2) (2026-08-06)
7
+
8
+
9
+ ### :rocket: New Features
10
+
11
+ * **layout:** 알림에 깊이를 만들고 그 구조로 토스트를 다시 짠다 ([6333945](https://github.com/hatiolab/operato/commit/6333945825a7bdca7019b2fd3fd39510beec0a15))
12
+
13
+
14
+ ### :sparkles: Styling
15
+
16
+ * **layout:** 토스트 왼쪽 강조 띠 제거 — 레벨은 아이콘 색만으로 ([a6639c3](https://github.com/hatiolab/operato/commit/a6639c38eb5831bb6d1b38377021488a232dbd0e))
17
+ * **layout:** 토스트 타이포·색·정렬·줄바꿈을 테마 위계에 맞춘다 ([0d4070f](https://github.com/hatiolab/operato/commit/0d4070f66e904bb4aab88e260c5963daefe12ff8))
18
+
19
+
20
+ ### :house: Code Refactoring
21
+
22
+ * **layout:** 토스트 AI 연결을 주입 방향으로 + 설정이 죽으면 감춘다 ([8dedafb](https://github.com/hatiolab/operato/commit/8dedafb184b74f7b99d1058f57a7f91fd3ba0f36))
23
+
24
+
25
+
26
+ ### [10.2.1](https://github.com/hatiolab/operato/compare/v10.2.0...v10.2.1) (2026-07-31)
27
+
28
+
29
+ ### :rocket: New Features
30
+
31
+ * **layout:** 헤더바·내비바에 경계선 훅 추가 ([7dab022](https://github.com/hatiolab/operato/commit/7dab022f94778119df3d76a6be7c5e00c92ba85d))
32
+
33
+
34
+
6
35
  ## [10.2.0](https://github.com/hatiolab/operato/compare/v10.1.0...v10.2.0) (2026-07-30)
7
36
 
8
37
 
@@ -1,22 +1,89 @@
1
1
  import { Action } from 'redux';
2
2
  export declare const OPEN_SNACKBAR = "OPEN_SNACKBAR";
3
3
  export declare const CLOSE_SNACKBAR = "CLOSE_SNACKBAR";
4
- export type NotificationLevel = 'info' | 'warn' | 'error';
4
+ /**
5
+ * 알림의 세 층
6
+ * ------------
7
+ * 이전에는 message 한 줄뿐이어서 "무슨 일이 있었나 / 왜 / 기술적 원문"이 한 문장에 섞였다.
8
+ * 실제 호출 210건을 보면 18건이 err?.message 를 그대로 본문에 넣고 있었다.
9
+ *
10
+ * message 사용자가 읽을 한 줄. 무슨 일이 일어났는가.
11
+ * detail 왜·어디서. 사용자가 다음 행동을 정하는 데 필요한 만큼.
12
+ * ex 기술적 원문(예외·스택). 접힌 상태로 두고 필요한 사람만 펼친다.
13
+ *
14
+ * level 은 success 를 포함한다. 이전 타입에는 없어서(info|warn|error) 성공 알림이 레벨 없이
15
+ * 호출되고 있었다 — 210건 중 117건이 그렇고 대부분 "…successfully" 문구다. 성공을 표현할
16
+ * 자리가 없으니 개발자가 레벨을 비웠고, 결과적으로 성공과 무성격 알림이 같게 보였다.
17
+ */
18
+ export type NotificationLevel = 'success' | 'info' | 'warn' | 'error';
5
19
  export type Notification = {
6
20
  message: string;
7
21
  level?: NotificationLevel;
22
+ /** 왜·어디서 — 한 단계 낮은 강조로 표시된다. */
23
+ detail?: string;
8
24
  option?: any;
25
+ /** 기술적 원문. 접힌 채로 전달되고, 펼치면 그대로 보인다. */
9
26
  ex?: any;
10
27
  };
28
+ /**
29
+ * 알림에서 곧바로 AI 도움으로 넘어가는 연결점.
30
+ *
31
+ * 방향은 **AI 어시스턴트 → 토스트 주입**이다. 토스트는 AI 를 알지 못하고, 찾아 나서지도 않는다.
32
+ * AI 를 제공하는 쪽이 "지금 도울 수 있다"고 판단했을 때 자기 함수를 넣어 준다.
33
+ *
34
+ * // AI 쪽에서
35
+ * registerNotifyAssistant(req => openAssistant(req)) // 쓸 수 있게 되면 주입
36
+ * registerNotifyAssistant(null) // 못 쓰게 되면 회수
37
+ *
38
+ * 가용 여부를 판단하는 책임도 주입하는 쪽에 있다. 설정 미비·권한 없음·백엔드 미응답처럼
39
+ * "AI 가 정상 동작하지 않는" 상태를 아는 것은 AI 쪽이지 토스트가 아니다. 그런 상태가 되면
40
+ * null 로 회수하면 되고, 그러면 토스트에서 버튼이 사라진다.
41
+ *
42
+ * 토스트는 주입된 것이 있는지만 본다. 그래서 AI 가 없는 앱, 설정이 죽은 앱에서는 이 기능이
43
+ * 화면에 아예 나타나지 않는다 — 눌러도 아무 일 없는 버튼이나, 열면 "쓸 수 없습니다"가 뜨는
44
+ * 버튼을 보여주지 않는다.
45
+ */
46
+ export type NotifyAssistantRequest = {
47
+ level: NotificationLevel;
48
+ message: string;
49
+ detail?: string;
50
+ ex?: any;
51
+ };
52
+ export type NotifyAssistantProvider = {
53
+ ask: (request: NotifyAssistantRequest) => void;
54
+ /**
55
+ * 지금 쓸 수 있는가. **렌더 시점마다** 호출되므로 값을 캐시하지 말고 그때의 상태를 답한다.
56
+ *
57
+ * 주입 후에 설정이 꺼지거나 세션이 끊기는 일이 있고, 그때 AI 쪽이 회수를 놓칠 수도 있다.
58
+ * 이 함수가 있으면 회수를 놓쳐도 버튼이 뜨지 않는다 — 기존 앱에 주는 영향을 최소로 두기 위한
59
+ * 안전장치다. 예외를 던지면 "쓸 수 없음"으로 본다.
60
+ *
61
+ * 생략하면 주입되어 있는 동안 항상 쓸 수 있다고 본다.
62
+ */
63
+ available?: () => boolean;
64
+ };
65
+ /** 함수만 주입하는 형태도 받는다(가용 여부를 따로 알릴 것이 없는 제공자). */
66
+ export type NotifyAssistant = ((request: NotifyAssistantRequest) => void) | NotifyAssistantProvider;
67
+ /** AI 쪽에서 주입한다. null 을 넣으면 회수되고 토스트에서 버튼이 사라진다. */
68
+ export declare function registerNotifyAssistant(assistant: NotifyAssistant | null): void;
69
+ /**
70
+ * 지금 실제로 쓸 수 있는 도움 함수. 주입이 없거나 available() 이 거짓이면 null.
71
+ * 토스트는 이 결과가 null 이 아닐 때만 버튼을 그린다.
72
+ */
73
+ export declare function resolveNotifyAssistant(): ((request: NotifyAssistantRequest) => void) | null;
11
74
  export declare function notify(notification: string | Notification): void;
12
75
  export type SnackbarAction = {
13
76
  type: 'OPEN_SNACKBAR' | 'CLOSE_SNACKBAR';
14
77
  level?: NotificationLevel;
15
78
  message?: string;
79
+ detail?: string;
80
+ ex?: any;
16
81
  action?: any;
17
82
  };
18
- export declare const showSnackbar: (level: NotificationLevel, { message, action, timer }: {
83
+ export declare const showSnackbar: (level: NotificationLevel, { message, detail, ex, action, timer }: {
19
84
  message: string;
85
+ detail?: string;
86
+ ex?: any;
20
87
  action?: any;
21
88
  timer?: number;
22
89
  }) => (dispatch: (param: SnackbarAction) => Action<any>) => void;
@@ -1,24 +1,70 @@
1
1
  export const OPEN_SNACKBAR = 'OPEN_SNACKBAR';
2
2
  export const CLOSE_SNACKBAR = 'CLOSE_SNACKBAR';
3
3
  var snackbarTimer;
4
+ /**
5
+ * 레벨별 기본 표시 시간(ms).
6
+ *
7
+ * error 는 -1 = 자동으로 닫지 않는다. 이전에는 모든 레벨이 5초라, 사용자가 눈을 돌린 사이
8
+ * 오류가 사라져 무엇이 잘못됐는지 알 수 없었다. 오류는 사람이 닫아야 사라지는 것이 맞다.
9
+ */
10
+ const DEFAULT_TIMER = {
11
+ success: 4000,
12
+ info: 4000,
13
+ warn: 8000,
14
+ error: -1
15
+ };
16
+ let notifyAssistant = null;
17
+ /** AI 쪽에서 주입한다. null 을 넣으면 회수되고 토스트에서 버튼이 사라진다. */
18
+ export function registerNotifyAssistant(assistant) {
19
+ notifyAssistant = assistant;
20
+ }
21
+ /**
22
+ * 지금 실제로 쓸 수 있는 도움 함수. 주입이 없거나 available() 이 거짓이면 null.
23
+ * 토스트는 이 결과가 null 이 아닐 때만 버튼을 그린다.
24
+ */
25
+ export function resolveNotifyAssistant() {
26
+ const provider = notifyAssistant;
27
+ if (!provider)
28
+ return null;
29
+ if (typeof provider === 'function')
30
+ return provider;
31
+ if (typeof provider.ask !== 'function')
32
+ return null;
33
+ if (provider.available) {
34
+ try {
35
+ if (!provider.available())
36
+ return null;
37
+ }
38
+ catch (_a) {
39
+ /* 가용 여부를 판단조차 못하는 상태면 쓸 수 없는 것으로 본다 */
40
+ return null;
41
+ }
42
+ }
43
+ return provider.ask;
44
+ }
4
45
  export function notify(notification) {
5
46
  if (typeof notification === 'string') {
6
47
  return notify({ message: notification });
7
48
  }
8
- var { message, level, option, ex } = notification;
49
+ var { message, level, detail, option, ex } = notification;
9
50
  document.dispatchEvent(new CustomEvent('notify', {
10
- detail: { message, level, ex, option }
51
+ detail: { message, level, detail, ex, option }
11
52
  }));
12
53
  }
13
- export const showSnackbar = (level, { message, action, timer = 5000 }) => (dispatch) => {
54
+ export const showSnackbar = (level, { message, detail, ex, action, timer }) => (dispatch) => {
55
+ var _a;
14
56
  dispatch({
15
57
  type: OPEN_SNACKBAR,
16
58
  level,
17
59
  message,
60
+ detail,
61
+ ex,
18
62
  action
19
63
  });
20
64
  window.clearTimeout(snackbarTimer);
21
- if (timer != -1)
22
- snackbarTimer = window.setTimeout(() => dispatch({ type: CLOSE_SNACKBAR }), timer);
65
+ /* 호출자가 timer 주지 않으면 레벨별 기본값을 쓴다 */
66
+ const effective = (_a = timer !== null && timer !== void 0 ? timer : DEFAULT_TIMER[level]) !== null && _a !== void 0 ? _a : 4000;
67
+ if (effective != -1)
68
+ snackbarTimer = window.setTimeout(() => dispatch({ type: CLOSE_SNACKBAR }), effective);
23
69
  };
24
70
  //# sourceMappingURL=snackbar.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"snackbar.js","sourceRoot":"","sources":["../../../src/actions/snackbar.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAA;AAC5C,MAAM,CAAC,MAAM,cAAc,GAAG,gBAAgB,CAAA;AAE9C,IAAI,aAAqB,CAAA;AAUzB,MAAM,UAAU,MAAM,CAAC,YAAmC;IACxD,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;QACrC,OAAO,MAAM,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAA;IAC1C,CAAC;IAED,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,YAA4B,CAAA;IAEjE,QAAQ,CAAC,aAAa,CACpB,IAAI,WAAW,CAAC,QAAQ,EAAE;QACxB,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE;KACvC,CAAC,CACH,CAAA;AACH,CAAC;AASD,MAAM,CAAC,MAAM,YAAY,GACvB,CACE,KAAwB,EACxB,EACE,OAAO,EACP,MAAM,EACN,KAAK,GAAG,IAAI,EAKb,EACD,EAAE,CACJ,CAAC,QAAgD,EAAE,EAAE;IACnD,QAAQ,CAAC;QACP,IAAI,EAAE,aAAa;QACnB,KAAK;QACL,OAAO;QACP,MAAM;KACP,CAAC,CAAA;IACF,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,CAAA;IAElC,IAAI,KAAK,IAAI,CAAC,CAAC;QAAE,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,EAAE,KAAK,CAAC,CAAA;AACrG,CAAC,CAAA","sourcesContent":["import { Action } from 'redux'\n\nexport const OPEN_SNACKBAR = 'OPEN_SNACKBAR'\nexport const CLOSE_SNACKBAR = 'CLOSE_SNACKBAR'\n\nvar snackbarTimer: number\n\nexport type NotificationLevel = 'info' | 'warn' | 'error'\nexport type Notification = {\n message: string\n level?: NotificationLevel\n option?: any\n ex?: any\n}\n\nexport function notify(notification: string | Notification): void {\n if (typeof notification === 'string') {\n return notify({ message: notification })\n }\n\n var { message, level, option, ex } = notification as Notification\n\n document.dispatchEvent(\n new CustomEvent('notify', {\n detail: { message, level, ex, option }\n })\n )\n}\n\nexport type SnackbarAction = {\n type: 'OPEN_SNACKBAR' | 'CLOSE_SNACKBAR'\n level?: NotificationLevel\n message?: string\n action?: any\n}\n\nexport const showSnackbar =\n (\n level: NotificationLevel,\n {\n message,\n action,\n timer = 5000\n }: {\n message: string\n action?: any\n timer?: number\n }\n ) =>\n (dispatch: (param: SnackbarAction) => Action<any>) => {\n dispatch({\n type: OPEN_SNACKBAR,\n level,\n message,\n action\n })\n window.clearTimeout(snackbarTimer)\n\n if (timer != -1) snackbarTimer = window.setTimeout(() => dispatch({ type: CLOSE_SNACKBAR }), timer)\n }\n"]}
1
+ {"version":3,"file":"snackbar.js","sourceRoot":"","sources":["../../../src/actions/snackbar.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAA;AAC5C,MAAM,CAAC,MAAM,cAAc,GAAG,gBAAgB,CAAA;AAE9C,IAAI,aAAqB,CAAA;AA2BzB;;;;;GAKG;AACH,MAAM,aAAa,GAAsC;IACvD,OAAO,EAAE,IAAI;IACb,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,CAAC,CAAC;CACV,CAAA;AA0CD,IAAI,eAAe,GAA2B,IAAI,CAAA;AAElD,mDAAmD;AACnD,MAAM,UAAU,uBAAuB,CAAC,SAAiC;IACvE,eAAe,GAAG,SAAS,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB;IACpC,MAAM,QAAQ,GAAG,eAAe,CAAA;IAChC,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAA;IAE1B,IAAI,OAAO,QAAQ,KAAK,UAAU;QAAE,OAAO,QAAQ,CAAA;IACnD,IAAI,OAAO,QAAQ,CAAC,GAAG,KAAK,UAAU;QAAE,OAAO,IAAI,CAAA;IAEnD,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;QACvB,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE;gBAAE,OAAO,IAAI,CAAA;QACxC,CAAC;QAAC,WAAM,CAAC;YACP,uCAAuC;YACvC,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC,GAAG,CAAA;AACrB,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,YAAmC;IACxD,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;QACrC,OAAO,MAAM,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAA;IAC1C,CAAC;IAED,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,YAA4B,CAAA;IAEzE,QAAQ,CAAC,aAAa,CACpB,IAAI,WAAW,CAAC,QAAQ,EAAE;QACxB,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE;KAC/C,CAAC,CACH,CAAA;AACH,CAAC;AAWD,MAAM,CAAC,MAAM,YAAY,GACvB,CACE,KAAwB,EACxB,EACE,OAAO,EACP,MAAM,EACN,EAAE,EACF,MAAM,EACN,KAAK,EAON,EACD,EAAE,CACJ,CAAC,QAAgD,EAAE,EAAE;;IACnD,QAAQ,CAAC;QACP,IAAI,EAAE,aAAa;QACnB,KAAK;QACL,OAAO;QACP,MAAM;QACN,EAAE;QACF,MAAM;KACP,CAAC,CAAA;IACF,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,CAAA;IAElC,qCAAqC;IACrC,MAAM,SAAS,GAAG,MAAA,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,aAAa,CAAC,KAAK,CAAC,mCAAI,IAAI,CAAA;IAEvD,IAAI,SAAS,IAAI,CAAC,CAAC;QAAE,aAAa,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,EAAE,SAAS,CAAC,CAAA;AAC7G,CAAC,CAAA","sourcesContent":["import { Action } from 'redux'\n\nexport const OPEN_SNACKBAR = 'OPEN_SNACKBAR'\nexport const CLOSE_SNACKBAR = 'CLOSE_SNACKBAR'\n\nvar snackbarTimer: number\n\n/**\n * 알림의 세 층\n * ------------\n * 이전에는 message 한 줄뿐이어서 \"무슨 일이 있었나 / 왜 / 기술적 원문\"이 한 문장에 섞였다.\n * 실제 호출 210건을 보면 18건이 err?.message 를 그대로 본문에 넣고 있었다.\n *\n * message 사용자가 읽을 한 줄. 무슨 일이 일어났는가.\n * detail 왜·어디서. 사용자가 다음 행동을 정하는 데 필요한 만큼.\n * ex 기술적 원문(예외·스택). 접힌 상태로 두고 필요한 사람만 펼친다.\n *\n * level 은 success 를 포함한다. 이전 타입에는 없어서(info|warn|error) 성공 알림이 레벨 없이\n * 호출되고 있었다 — 210건 중 117건이 그렇고 대부분 \"…successfully\" 문구다. 성공을 표현할\n * 자리가 없으니 개발자가 레벨을 비웠고, 결과적으로 성공과 무성격 알림이 같게 보였다.\n */\nexport type NotificationLevel = 'success' | 'info' | 'warn' | 'error'\nexport type Notification = {\n message: string\n level?: NotificationLevel\n /** 왜·어디서 — 한 단계 낮은 강조로 표시된다. */\n detail?: string\n option?: any\n /** 기술적 원문. 접힌 채로 전달되고, 펼치면 그대로 보인다. */\n ex?: any\n}\n\n/**\n * 레벨별 기본 표시 시간(ms).\n *\n * error 는 -1 = 자동으로 닫지 않는다. 이전에는 모든 레벨이 5초라, 사용자가 눈을 돌린 사이\n * 오류가 사라져 무엇이 잘못됐는지 알 수 없었다. 오류는 사람이 닫아야 사라지는 것이 맞다.\n */\nconst DEFAULT_TIMER: Record<NotificationLevel, number> = {\n success: 4000,\n info: 4000,\n warn: 8000,\n error: -1\n}\n\n/**\n * 알림에서 곧바로 AI 도움으로 넘어가는 연결점.\n *\n * 방향은 **AI 어시스턴트 → 토스트 주입**이다. 토스트는 AI 를 알지 못하고, 찾아 나서지도 않는다.\n * AI 를 제공하는 쪽이 \"지금 도울 수 있다\"고 판단했을 때 자기 함수를 넣어 준다.\n *\n * // AI 쪽에서\n * registerNotifyAssistant(req => openAssistant(req)) // 쓸 수 있게 되면 주입\n * registerNotifyAssistant(null) // 못 쓰게 되면 회수\n *\n * 가용 여부를 판단하는 책임도 주입하는 쪽에 있다. 설정 미비·권한 없음·백엔드 미응답처럼\n * \"AI 가 정상 동작하지 않는\" 상태를 아는 것은 AI 쪽이지 토스트가 아니다. 그런 상태가 되면\n * null 로 회수하면 되고, 그러면 토스트에서 버튼이 사라진다.\n *\n * 토스트는 주입된 것이 있는지만 본다. 그래서 AI 가 없는 앱, 설정이 죽은 앱에서는 이 기능이\n * 화면에 아예 나타나지 않는다 — 눌러도 아무 일 없는 버튼이나, 열면 \"쓸 수 없습니다\"가 뜨는\n * 버튼을 보여주지 않는다.\n */\nexport type NotifyAssistantRequest = {\n level: NotificationLevel\n message: string\n detail?: string\n ex?: any\n}\nexport type NotifyAssistantProvider = {\n ask: (request: NotifyAssistantRequest) => void\n /**\n * 지금 쓸 수 있는가. **렌더 시점마다** 호출되므로 값을 캐시하지 말고 그때의 상태를 답한다.\n *\n * 주입 후에 설정이 꺼지거나 세션이 끊기는 일이 있고, 그때 AI 쪽이 회수를 놓칠 수도 있다.\n * 이 함수가 있으면 회수를 놓쳐도 버튼이 뜨지 않는다 — 기존 앱에 주는 영향을 최소로 두기 위한\n * 안전장치다. 예외를 던지면 \"쓸 수 없음\"으로 본다.\n *\n * 생략하면 주입되어 있는 동안 항상 쓸 수 있다고 본다.\n */\n available?: () => boolean\n}\n/** 함수만 주입하는 형태도 받는다(가용 여부를 따로 알릴 것이 없는 제공자). */\nexport type NotifyAssistant = ((request: NotifyAssistantRequest) => void) | NotifyAssistantProvider\n\nlet notifyAssistant: NotifyAssistant | null = null\n\n/** AI 쪽에서 주입한다. null 을 넣으면 회수되고 토스트에서 버튼이 사라진다. */\nexport function registerNotifyAssistant(assistant: NotifyAssistant | null): void {\n notifyAssistant = assistant\n}\n\n/**\n * 지금 실제로 쓸 수 있는 도움 함수. 주입이 없거나 available() 이 거짓이면 null.\n * 토스트는 이 결과가 null 이 아닐 때만 버튼을 그린다.\n */\nexport function resolveNotifyAssistant(): ((request: NotifyAssistantRequest) => void) | null {\n const provider = notifyAssistant\n if (!provider) return null\n\n if (typeof provider === 'function') return provider\n if (typeof provider.ask !== 'function') return null\n\n if (provider.available) {\n try {\n if (!provider.available()) return null\n } catch {\n /* 가용 여부를 판단조차 못하는 상태면 쓸 수 없는 것으로 본다 */\n return null\n }\n }\n\n return provider.ask\n}\n\nexport function notify(notification: string | Notification): void {\n if (typeof notification === 'string') {\n return notify({ message: notification })\n }\n\n var { message, level, detail, option, ex } = notification as Notification\n\n document.dispatchEvent(\n new CustomEvent('notify', {\n detail: { message, level, detail, ex, option }\n })\n )\n}\n\nexport type SnackbarAction = {\n type: 'OPEN_SNACKBAR' | 'CLOSE_SNACKBAR'\n level?: NotificationLevel\n message?: string\n detail?: string\n ex?: any\n action?: any\n}\n\nexport const showSnackbar =\n (\n level: NotificationLevel,\n {\n message,\n detail,\n ex,\n action,\n timer\n }: {\n message: string\n detail?: string\n ex?: any\n action?: any\n timer?: number\n }\n ) =>\n (dispatch: (param: SnackbarAction) => Action<any>) => {\n dispatch({\n type: OPEN_SNACKBAR,\n level,\n message,\n detail,\n ex,\n action\n })\n window.clearTimeout(snackbarTimer)\n\n /* 호출자가 timer 를 주지 않으면 레벨별 기본값을 쓴다 */\n const effective = timer ?? DEFAULT_TIMER[level] ?? 4000\n\n if (effective != -1) snackbarTimer = window.setTimeout(() => dispatch({ type: CLOSE_SNACKBAR }), effective)\n }\n"]}
@@ -26,22 +26,28 @@ document.addEventListener('open-popup', event => {
26
26
  callback(popup);
27
27
  });
28
28
  document.addEventListener('notify', event => {
29
- let { message, level, ex = '', option = {} } = event.detail;
30
- switch (level) {
29
+ let { message, level, detail, ex = '', option = {} } = event.detail;
30
+ /*
31
+ * 레벨을 주지 않은 호출이 210건 중 117건이다. 그대로 두면 성격 없는 알림이 되어 화면에서
32
+ * 성공·안내가 구분되지 않으므로 info 로 정규화한다. (성공 알림은 호출부에서 점차
33
+ * level: 'success' 로 옮긴다 — 기본값이 잡혀 있으면 그 전에도 화면은 일관된다.)
34
+ */
35
+ const effectiveLevel = level || 'info';
36
+ switch (effectiveLevel) {
31
37
  case 'error':
32
38
  console.error(message, ex);
33
39
  break;
34
40
  case 'warn':
35
41
  console.warn(message, ex);
36
42
  break;
37
- case 'info':
38
- console.info(message);
39
- break;
40
43
  default:
44
+ console.info(message);
41
45
  break;
42
46
  }
43
- store.dispatch(showSnackbar(level, {
47
+ store.dispatch(showSnackbar(effectiveLevel, {
44
48
  message,
49
+ detail,
50
+ ex,
45
51
  ...option
46
52
  }));
47
53
  });
@@ -1 +1 @@
1
- {"version":3,"file":"initializer.js","sourceRoot":"","sources":["../../src/initializer.ts"],"names":[],"mappings":"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","sourcesContent":["import { REGISTER_NAVIGATION_CALLBACK, store } from '@operato/shell'\nimport { UPDATE_VIEWPART, closeOverlay, openOverlay, openPopup, toggleOverlay } from './actions/layout.js'\n\nimport layout from './reducers/layout.js'\nimport { showSnackbar } from './actions/snackbar.js'\nimport snackbar from './reducers/snackbar.js'\n\nstore.addReducers({\n layout,\n snackbar\n})\n\ndocument.addEventListener('open-overlay', event => {\n const { name, options } = (event as CustomEvent).detail\n openOverlay(name, options)\n})\n\ndocument.addEventListener('close-overlay', event => {\n const { name } = (event as CustomEvent).detail\n closeOverlay(name)\n})\n\ndocument.addEventListener('toggle-overlay', event => {\n const { name, options } = (event as CustomEvent).detail\n toggleOverlay(name, options)\n})\n\ndocument.addEventListener('open-popup', event => {\n const { template, options, callback } = (event as CustomEvent).detail\n var popup = openPopup(template, options)\n if (popup && callback) callback(popup)\n})\n\ndocument.addEventListener('notify', event => {\n let { message, level, ex = '', option = {} } = (event as CustomEvent).detail\n\n switch (level) {\n case 'error':\n console.error(message, ex)\n break\n case 'warn':\n console.warn(message, ex)\n break\n case 'info':\n console.info(message)\n break\n default:\n break\n }\n\n store.dispatch(\n showSnackbar(level, {\n message,\n ...(option as {\n action?: any\n timer?: number\n })\n }) as any\n )\n})\n\n/* overlay handling */\nvar overlayStack: any[] = []\nfunction getLastSequence() {\n return overlayStack.length > 0 ? overlayStack[overlayStack.length - 1].overlay.sequence : -1\n}\n\ndocument.addEventListener('keydown', event => {\n if (overlayStack.length > 0 && (event.key === 'Escape' || event.key === 'Esc')) {\n history.state?.overlay?.escapable && history.back()\n }\n})\n\nconst historyHandler = (location: string, event: Event) => {\n var navigated = event instanceof PopStateEvent\n\n var state = history.state\n var overlay = state?.overlay\n var sequence = overlay?.sequence || -1\n\n var lastSequence = getLastSequence()\n\n if (overlayStack.length > 0 && sequence < lastSequence) {\n /* overlay 관련 history가 아닌 경우. */\n do {\n let { overlay } = overlayStack.pop()\n store.dispatch({\n type: UPDATE_VIEWPART,\n name: overlay.name,\n override: { show: false }\n })\n\n lastSequence = getLastSequence()\n } while (sequence < lastSequence)\n }\n\n if (!navigated && overlay) {\n overlayStack.push({ ...state })\n\n store.dispatch({\n type: UPDATE_VIEWPART,\n name: overlay.name,\n override: { show: true }\n })\n }\n}\n\nstore.dispatch({\n type: REGISTER_NAVIGATION_CALLBACK,\n callback: historyHandler\n})\n\nexport default store\n"]}
1
+ {"version":3,"file":"initializer.js","sourceRoot":"","sources":["../../src/initializer.ts"],"names":[],"mappings":"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","sourcesContent":["import { REGISTER_NAVIGATION_CALLBACK, store } from '@operato/shell'\nimport { UPDATE_VIEWPART, closeOverlay, openOverlay, openPopup, toggleOverlay } from './actions/layout.js'\n\nimport layout from './reducers/layout.js'\nimport { showSnackbar } from './actions/snackbar.js'\nimport snackbar from './reducers/snackbar.js'\n\nstore.addReducers({\n layout,\n snackbar\n})\n\ndocument.addEventListener('open-overlay', event => {\n const { name, options } = (event as CustomEvent).detail\n openOverlay(name, options)\n})\n\ndocument.addEventListener('close-overlay', event => {\n const { name } = (event as CustomEvent).detail\n closeOverlay(name)\n})\n\ndocument.addEventListener('toggle-overlay', event => {\n const { name, options } = (event as CustomEvent).detail\n toggleOverlay(name, options)\n})\n\ndocument.addEventListener('open-popup', event => {\n const { template, options, callback } = (event as CustomEvent).detail\n var popup = openPopup(template, options)\n if (popup && callback) callback(popup)\n})\n\ndocument.addEventListener('notify', event => {\n let { message, level, detail, ex = '', option = {} } = (event as CustomEvent).detail\n\n /*\n * 레벨을 주지 않은 호출이 210건 중 117건이다. 그대로 두면 성격 없는 알림이 되어 화면에서\n * 성공·안내가 구분되지 않으므로 info 로 정규화한다. (성공 알림은 호출부에서 점차\n * level: 'success' 로 옮긴다 — 기본값이 잡혀 있으면 그 전에도 화면은 일관된다.)\n */\n const effectiveLevel = level || 'info'\n\n switch (effectiveLevel) {\n case 'error':\n console.error(message, ex)\n break\n case 'warn':\n console.warn(message, ex)\n break\n default:\n console.info(message)\n break\n }\n\n store.dispatch(\n showSnackbar(effectiveLevel, {\n message,\n detail,\n ex,\n ...(option as {\n action?: any\n timer?: number\n })\n }) as any\n )\n})\n\n/* overlay handling */\nvar overlayStack: any[] = []\nfunction getLastSequence() {\n return overlayStack.length > 0 ? overlayStack[overlayStack.length - 1].overlay.sequence : -1\n}\n\ndocument.addEventListener('keydown', event => {\n if (overlayStack.length > 0 && (event.key === 'Escape' || event.key === 'Esc')) {\n history.state?.overlay?.escapable && history.back()\n }\n})\n\nconst historyHandler = (location: string, event: Event) => {\n var navigated = event instanceof PopStateEvent\n\n var state = history.state\n var overlay = state?.overlay\n var sequence = overlay?.sequence || -1\n\n var lastSequence = getLastSequence()\n\n if (overlayStack.length > 0 && sequence < lastSequence) {\n /* overlay 관련 history가 아닌 경우. */\n do {\n let { overlay } = overlayStack.pop()\n store.dispatch({\n type: UPDATE_VIEWPART,\n name: overlay.name,\n override: { show: false }\n })\n\n lastSequence = getLastSequence()\n } while (sequence < lastSequence)\n }\n\n if (!navigated && overlay) {\n overlayStack.push({ ...state })\n\n store.dispatch({\n type: UPDATE_VIEWPART,\n name: overlay.name,\n override: { show: true }\n })\n }\n}\n\nstore.dispatch({\n type: REGISTER_NAVIGATION_CALLBACK,\n callback: historyHandler\n})\n\nexport default store\n"]}
@@ -87,6 +87,9 @@ HeaderBar.styles = [
87
87
  position: relative;
88
88
 
89
89
  background-color: var(--header-bar-background-color);
90
+ /* 본문과 색차가 작은 팔레트에서도 크롬 경계가 남도록 (--nav-bar-border 와 같은 취지) */
91
+ border-bottom: var(--header-bar-border, none);
92
+ box-sizing: border-box;
90
93
  }
91
94
 
92
95
  *[headerbar] {
@@ -1 +1 @@
1
- {"version":3,"file":"ox-header-bar.js","sourceRoot":"","sources":["../../../src/layouts/ox-header-bar.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/popup/ox-floating-overlay.js'\nimport '../components/ox-resize-splitter.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { customElement, property } from 'lit/decorators.js'\nimport { LayoutController } from '@operato/shell'\n\nimport { Viewpart, VIEWPART_LEVEL } from '../actions/layout.js'\n\n@customElement('ox-header-bar')\nclass HeaderBar extends LitElement {\n static styles = [\n css`\n :host {\n display: flex;\n flex-flow: column nowrap;\n align-items: stretch;\n\n position: relative;\n\n background-color: var(--header-bar-background-color);\n }\n\n *[headerbar] {\n display: block;\n }\n `\n ]\n\n private _layout = new LayoutController(this)\n\n @property({ type: Boolean, attribute: 'fullbleed' }) fullbleed: boolean = false\n\n private _startHeight: number = 0\n\n render() {\n var viewparts = this._layout.viewparts\n var headerbars = Object.keys(viewparts)\n .map(name => {\n return {\n name,\n ...viewparts[name]\n }\n })\n .filter(viewpart => viewpart.position == 'headerbar' && (!this.fullbleed || viewpart.hovering))\n\n headerbars = [\n ...headerbars.filter(viewpart => viewpart.level == VIEWPART_LEVEL.TOPMOST),\n ...headerbars.filter(viewpart => viewpart.level !== VIEWPART_LEVEL.TOPMOST)\n ]\n\n return html`\n ${headerbars.map(headerbar =>\n !headerbar.show\n ? html``\n : headerbar.hovering\n ? html`\n <ox-floating-overlay\n .backdrop=${headerbar.backdrop}\n direction=\"down\"\n .hovering=${headerbar.hovering}\n .name=${headerbar.name}\n .title=${headerbar.title}\n .help=${headerbar.help}\n .size=${headerbar.size}\n .closable=${headerbar.closable}\n .templateProperties=${headerbar.templateProperties}\n .historical=${true}\n .search=${headerbar.search}\n .movable=${headerbar.movable}\n .filter=${headerbar.filter}\n z-index=${ifDefined(headerbar.zIndex)}\n >${headerbar.template}</ox-floating-overlay\n >\n `\n : html`\n <div headerbar>${headerbar.template}</div>\n ${headerbar.resizable\n ? html`\n <ox-resize-splitter\n @splitter-dragstart=${(e: CustomEvent) => this.resizeStart(e)}\n @splitter-drag=${(e: CustomEvent) => this.resizeDrag(e)}\n ></ox-resize-splitter>\n `\n : html``}\n `\n )}\n `\n }\n\n resizeStart(e: CustomEvent) {\n this._startHeight = ((e.target as HTMLElement)?.previousElementSibling as HTMLElement).offsetHeight\n }\n\n resizeDrag(e: CustomEvent) {\n var delta = e.detail\n\n var x = ((e.target as HTMLElement)?.previousElementSibling as HTMLElement).children\n Array.from(x).forEach(ele => {\n ;(ele as HTMLElement).style.height = `${this._startHeight + delta.y}px`\n })\n }\n\n}\n"]}
1
+ {"version":3,"file":"ox-header-bar.js","sourceRoot":"","sources":["../../../src/layouts/ox-header-bar.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/popup/ox-floating-overlay.js'\nimport '../components/ox-resize-splitter.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { customElement, property } from 'lit/decorators.js'\nimport { LayoutController } from '@operato/shell'\n\nimport { Viewpart, VIEWPART_LEVEL } from '../actions/layout.js'\n\n@customElement('ox-header-bar')\nclass HeaderBar extends LitElement {\n static styles = [\n css`\n :host {\n display: flex;\n flex-flow: column nowrap;\n align-items: stretch;\n\n position: relative;\n\n background-color: var(--header-bar-background-color);\n /* 본문과 색차가 작은 팔레트에서도 크롬 경계가 남도록 (--nav-bar-border 와 같은 취지) */\n border-bottom: var(--header-bar-border, none);\n box-sizing: border-box;\n }\n\n *[headerbar] {\n display: block;\n }\n `\n ]\n\n private _layout = new LayoutController(this)\n\n @property({ type: Boolean, attribute: 'fullbleed' }) fullbleed: boolean = false\n\n private _startHeight: number = 0\n\n render() {\n var viewparts = this._layout.viewparts\n var headerbars = Object.keys(viewparts)\n .map(name => {\n return {\n name,\n ...viewparts[name]\n }\n })\n .filter(viewpart => viewpart.position == 'headerbar' && (!this.fullbleed || viewpart.hovering))\n\n headerbars = [\n ...headerbars.filter(viewpart => viewpart.level == VIEWPART_LEVEL.TOPMOST),\n ...headerbars.filter(viewpart => viewpart.level !== VIEWPART_LEVEL.TOPMOST)\n ]\n\n return html`\n ${headerbars.map(headerbar =>\n !headerbar.show\n ? html``\n : headerbar.hovering\n ? html`\n <ox-floating-overlay\n .backdrop=${headerbar.backdrop}\n direction=\"down\"\n .hovering=${headerbar.hovering}\n .name=${headerbar.name}\n .title=${headerbar.title}\n .help=${headerbar.help}\n .size=${headerbar.size}\n .closable=${headerbar.closable}\n .templateProperties=${headerbar.templateProperties}\n .historical=${true}\n .search=${headerbar.search}\n .movable=${headerbar.movable}\n .filter=${headerbar.filter}\n z-index=${ifDefined(headerbar.zIndex)}\n >${headerbar.template}</ox-floating-overlay\n >\n `\n : html`\n <div headerbar>${headerbar.template}</div>\n ${headerbar.resizable\n ? html`\n <ox-resize-splitter\n @splitter-dragstart=${(e: CustomEvent) => this.resizeStart(e)}\n @splitter-drag=${(e: CustomEvent) => this.resizeDrag(e)}\n ></ox-resize-splitter>\n `\n : html``}\n `\n )}\n `\n }\n\n resizeStart(e: CustomEvent) {\n this._startHeight = ((e.target as HTMLElement)?.previousElementSibling as HTMLElement).offsetHeight\n }\n\n resizeDrag(e: CustomEvent) {\n var delta = e.detail\n\n var x = ((e.target as HTMLElement)?.previousElementSibling as HTMLElement).children\n Array.from(x).forEach(ele => {\n ;(ele as HTMLElement).style.height = `${this._startHeight + delta.y}px`\n })\n }\n\n}\n"]}
@@ -90,6 +90,12 @@ NavBar.styles = [
90
90
  position: relative;
91
91
 
92
92
  background-color: var(--nav-bar-background-color);
93
+ /*
94
+ * 레일과 본문 배경이 팔레트에 따라 거의 같은 값이 될 수 있어(operato-board 다크에서
95
+ * 대비 1.02) 경계가 사라졌다. 색차에만 기대지 않도록 경계선을 둔다.
96
+ */
97
+ border-right: var(--nav-bar-border, none);
98
+ box-sizing: border-box;
93
99
  }
94
100
 
95
101
  *[navbar] {
@@ -1 +1 @@
1
- {"version":3,"file":"ox-nav-bar.js","sourceRoot":"","sources":["../../../src/layouts/ox-nav-bar.ts"],"names":[],"mappings":";AAAA,OAAO,uCAAuC,CAAA;AAC9C,OAAO,qCAAqC,CAAA;AAE5C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEjD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEjD,OAAO,EAAY,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAG/D,IAAM,MAAM,GAAZ,MAAM,MAAO,SAAQ,UAAU;IAA/B;;QAqBU,YAAO,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAA;QAES,cAAS,GAAY,KAAK,CAAA;QAEvE,gBAAW,GAAW,CAAC,CAAA;IAuEjC,CAAC;IArEC,MAAM;QACJ,IAAI,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAA;QACtC,IAAI,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC;aACjC,GAAG,CAAC,IAAI,CAAC,EAAE;YACV,OAAO;gBACL,IAAI;gBACJ,GAAG,SAAS,CAAC,IAAI,CAAC;aACnB,CAAA;QACH,CAAC,CAAC;aACD,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,IAAI,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAA;QAE9F,OAAO,GAAG;YACR,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,IAAI,cAAc,CAAC,OAAO,CAAC;YACvE,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,KAAK,cAAc,CAAC,OAAO,CAAC;SACzE,CAAA;QAED,OAAO,IAAI,CAAA;QACP,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CACrB,CAAC,MAAM,CAAC,IAAI;YACV,CAAC,CAAC,IAAI,CAAA,EAAE;YACR,CAAC,CAAC,MAAM,CAAC,QAAQ;gBACf,CAAC,CAAC,IAAI,CAAA;;8BAEY,MAAM,CAAC,QAAQ;;8BAEf,MAAM,CAAC,QAAQ;0BACnB,MAAM,CAAC,IAAI;2BACV,MAAM,CAAC,KAAK;0BACb,MAAM,CAAC,IAAI;0BACX,MAAM,CAAC,IAAI;8BACP,MAAM,CAAC,QAAQ;wCACL,MAAM,CAAC,kBAAkB;gCACjC,IAAI;4BACR,MAAM,CAAC,MAAM;6BACZ,MAAM,CAAC,OAAO;4BACf,MAAM,CAAC,MAAM;4BACb,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC;qBAC/B,MAAM,CAAC,QAAQ;;eAErB;gBACH,CAAC,CAAC,IAAI,CAAA;8BACY,MAAM,CAAC,QAAQ;kBAC3B,MAAM,CAAC,SAAS;oBAChB,CAAC,CAAC,IAAI,CAAA;;8CAEsB,CAAC,CAAc,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;yCAC5C,CAAC,CAAc,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;;;qBAG1D;oBACH,CAAC,CAAC,IAAI,CAAA,EAAE;eACX,CACR;KACF,CAAA;IACH,CAAC;IAED,WAAW,CAAC,CAAc;;QACxB,IAAI,CAAC,WAAW,GAAG,CAAC,MAAC,CAAC,CAAC,MAAsB,0CAAE,sBAAsC,CAAA,CAAC,WAAW,CAAA;IACnG,CAAC;IAED,UAAU,CAAC,CAAc;;QACvB,IAAI,KAAK,GAAG,CAAC,CAAC,MAAM,CAAA;QAEpB,IAAI,CAAC,GAAG,CAAC,MAAC,CAAC,CAAC,MAAsB,0CAAE,sBAAsC,CAAA,CAAC,QAAQ,CAAA;QACnF,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;YAC1B,CAAC;YAAC,GAAmB,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC,CAAC,IAAI,CAAA;QACvE,CAAC,CAAC,CAAA;IACJ,CAAC;;AA7FM,aAAM,GAAG;IACd,eAAe;IACf,GAAG,CAAA;;;;;;;;;;;;;;;KAeF;CACF,AAlBY,CAkBZ;AAIoD;IAApD,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;yCAA2B;AAvB3E,MAAM;IADX,aAAa,CAAC,YAAY,CAAC;GACtB,MAAM,CAgGX","sourcesContent":["import '@operato/popup/ox-floating-overlay.js'\nimport '../components/ox-resize-splitter.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { customElement, property } from 'lit/decorators.js'\nimport { LayoutController } from '@operato/shell'\n\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { Viewpart, VIEWPART_LEVEL } from '../actions/layout.js'\n\n@customElement('ox-nav-bar')\nclass NavBar extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-flow: row nowrap;\n align-items: stretch;\n\n position: relative;\n\n background-color: var(--nav-bar-background-color);\n }\n\n *[navbar] {\n display: flex;\n flex-direction: row;\n }\n `\n ]\n\n private _layout = new LayoutController(this)\n\n @property({ type: Boolean, attribute: 'fullbleed' }) fullbleed: boolean = false\n\n private _startWidth: number = 0\n\n render() {\n var viewparts = this._layout.viewparts\n var navbars = Object.keys(viewparts)\n .map(name => {\n return {\n name,\n ...viewparts[name]\n }\n })\n .filter(viewpart => viewpart.position == 'navbar' && (!this.fullbleed || viewpart.hovering))\n\n navbars = [\n ...navbars.filter(viewpart => viewpart.level == VIEWPART_LEVEL.TOPMOST),\n ...navbars.filter(viewpart => viewpart.level !== VIEWPART_LEVEL.TOPMOST)\n ]\n\n return html`\n ${navbars.map(navbar =>\n !navbar.show\n ? html``\n : navbar.hovering\n ? html`\n <ox-floating-overlay\n .backdrop=${navbar.backdrop}\n direction=\"right\"\n .hovering=${navbar.hovering}\n .name=${navbar.name}\n .title=${navbar.title}\n .help=${navbar.help}\n .size=${navbar.size}\n .closable=${navbar.closable}\n .templateProperties=${navbar.templateProperties}\n .historical=${true}\n .search=${navbar.search}\n .movable=${navbar.movable}\n .filter=${navbar.filter}\n z-index=${ifDefined(navbar.zIndex)}\n >${navbar.template}</ox-floating-overlay\n >\n `\n : html`\n <div navbar>${navbar.template}</div>\n ${navbar.resizable\n ? html`\n <ox-resize-splitter\n @splitter-dragstart=${(e: CustomEvent) => this.resizeStart(e)}\n @splitter-drag=${(e: CustomEvent) => this.resizeDrag(e)}\n vertical\n ></ox-resize-splitter>\n `\n : html``}\n `\n )}\n `\n }\n\n resizeStart(e: CustomEvent) {\n this._startWidth = ((e.target as HTMLElement)?.previousElementSibling as HTMLElement).offsetWidth\n }\n\n resizeDrag(e: CustomEvent) {\n var delta = e.detail\n\n var x = ((e.target as HTMLElement)?.previousElementSibling as HTMLElement).children\n Array.from(x).forEach(ele => {\n ;(ele as HTMLElement).style.width = `${this._startWidth + delta.x}px`\n })\n }\n\n}\n"]}
1
+ {"version":3,"file":"ox-nav-bar.js","sourceRoot":"","sources":["../../../src/layouts/ox-nav-bar.ts"],"names":[],"mappings":"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","sourcesContent":["import '@operato/popup/ox-floating-overlay.js'\nimport '../components/ox-resize-splitter.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { ifDefined } from 'lit/directives/if-defined.js'\nimport { customElement, property } from 'lit/decorators.js'\nimport { LayoutController } from '@operato/shell'\n\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { Viewpart, VIEWPART_LEVEL } from '../actions/layout.js'\n\n@customElement('ox-nav-bar')\nclass NavBar extends LitElement {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-flow: row nowrap;\n align-items: stretch;\n\n position: relative;\n\n background-color: var(--nav-bar-background-color);\n /*\n * 레일과 본문 배경이 팔레트에 따라 거의 같은 값이 될 수 있어(operato-board 다크에서\n * 대비 1.02) 경계가 사라졌다. 색차에만 기대지 않도록 경계선을 둔다.\n */\n border-right: var(--nav-bar-border, none);\n box-sizing: border-box;\n }\n\n *[navbar] {\n display: flex;\n flex-direction: row;\n }\n `\n ]\n\n private _layout = new LayoutController(this)\n\n @property({ type: Boolean, attribute: 'fullbleed' }) fullbleed: boolean = false\n\n private _startWidth: number = 0\n\n render() {\n var viewparts = this._layout.viewparts\n var navbars = Object.keys(viewparts)\n .map(name => {\n return {\n name,\n ...viewparts[name]\n }\n })\n .filter(viewpart => viewpart.position == 'navbar' && (!this.fullbleed || viewpart.hovering))\n\n navbars = [\n ...navbars.filter(viewpart => viewpart.level == VIEWPART_LEVEL.TOPMOST),\n ...navbars.filter(viewpart => viewpart.level !== VIEWPART_LEVEL.TOPMOST)\n ]\n\n return html`\n ${navbars.map(navbar =>\n !navbar.show\n ? html``\n : navbar.hovering\n ? html`\n <ox-floating-overlay\n .backdrop=${navbar.backdrop}\n direction=\"right\"\n .hovering=${navbar.hovering}\n .name=${navbar.name}\n .title=${navbar.title}\n .help=${navbar.help}\n .size=${navbar.size}\n .closable=${navbar.closable}\n .templateProperties=${navbar.templateProperties}\n .historical=${true}\n .search=${navbar.search}\n .movable=${navbar.movable}\n .filter=${navbar.filter}\n z-index=${ifDefined(navbar.zIndex)}\n >${navbar.template}</ox-floating-overlay\n >\n `\n : html`\n <div navbar>${navbar.template}</div>\n ${navbar.resizable\n ? html`\n <ox-resize-splitter\n @splitter-dragstart=${(e: CustomEvent) => this.resizeStart(e)}\n @splitter-drag=${(e: CustomEvent) => this.resizeDrag(e)}\n vertical\n ></ox-resize-splitter>\n `\n : html``}\n `\n )}\n `\n }\n\n resizeStart(e: CustomEvent) {\n this._startWidth = ((e.target as HTMLElement)?.previousElementSibling as HTMLElement).offsetWidth\n }\n\n resizeDrag(e: CustomEvent) {\n var delta = e.detail\n\n var x = ((e.target as HTMLElement)?.previousElementSibling as HTMLElement).children\n Array.from(x).forEach(ele => {\n ;(ele as HTMLElement).style.width = `${this._startWidth + delta.x}px`\n })\n }\n\n}\n"]}
@@ -1,2 +1,2 @@
1
- import '@material/web/button/filled-button.js';
1
+ import '@material/web/button/text-button.js';
2
2
  import '@material/web/icon/icon.js';