jky-component-lib 0.0.67 → 0.0.72

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.
Files changed (37) hide show
  1. package/dist/es/form/Form.vue.d.ts +8 -8
  2. package/dist/es/menu/Menu.vue.d.ts +5 -4
  3. package/dist/es/menu/Menu.vue.js +63 -70
  4. package/dist/es/menu/MenuItem.vue.d.ts +7 -0
  5. package/dist/es/menu/MenuItem.vue.js +67 -0
  6. package/dist/es/menu/MenuItem.vue2.js +4 -0
  7. package/dist/es/menu/style.css +3 -2
  8. package/dist/es/package.json.js +1 -1
  9. package/dist/es/page-layout/PageLayout.vue.d.ts +11 -31
  10. package/dist/es/page-layout/PageLayout.vue.js +274 -103
  11. package/dist/es/page-layout/style.css +59 -0
  12. package/dist/es/page-table/PageTable.vue.d.ts +28 -28
  13. package/dist/es/style.css +1017 -42
  14. package/dist/es/styles.css +1 -1
  15. package/dist/es/tabs/Tabs.vue.js +47 -11
  16. package/dist/lib/form/Form.vue.d.ts +8 -8
  17. package/dist/lib/menu/Menu.vue.d.ts +5 -4
  18. package/dist/lib/menu/Menu.vue.js +62 -69
  19. package/dist/lib/menu/MenuItem.vue.d.ts +7 -0
  20. package/dist/lib/menu/MenuItem.vue.js +67 -0
  21. package/dist/lib/menu/MenuItem.vue2.js +4 -0
  22. package/dist/lib/menu/style.css +3 -2
  23. package/dist/lib/package.json.js +1 -1
  24. package/dist/lib/page-layout/PageLayout.vue.d.ts +11 -31
  25. package/dist/lib/page-layout/PageLayout.vue.js +273 -102
  26. package/dist/lib/page-layout/style.css +59 -0
  27. package/dist/lib/page-table/PageTable.vue.d.ts +28 -28
  28. package/dist/lib/style.css +1017 -42
  29. package/dist/lib/styles.css +1 -1
  30. package/dist/lib/tabs/Tabs.vue.js +47 -11
  31. package/package.json +12 -3
  32. package/dist/es/menu/Aside.vue.d.ts +0 -17
  33. package/dist/es/menu/Aside.vue.js +0 -44
  34. package/dist/es/menu/Aside.vue2.js +0 -4
  35. package/dist/lib/menu/Aside.vue.d.ts +0 -17
  36. package/dist/lib/menu/Aside.vue.js +0 -44
  37. package/dist/lib/menu/Aside.vue2.js +0 -4
@@ -18,134 +18,305 @@ var __spreadValues = (a, b) => {
18
18
  return a;
19
19
  };
20
20
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
+ var __objRest = (source, exclude) => {
22
+ var target = {};
23
+ for (var prop in source)
24
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
25
+ target[prop] = source[prop];
26
+ if (source != null && __getOwnPropSymbols)
27
+ for (var prop of __getOwnPropSymbols(source)) {
28
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
29
+ target[prop] = source[prop];
30
+ }
31
+ return target;
32
+ };
21
33
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
22
34
  const vue = require("vue");
23
35
  const ElementPlus = require("element-plus");
24
- const _hoisted_1 = {
25
- class: "jky-page-layout flex h-full w-full overflow-hidden",
26
- style: { "--el-menu-border-color": "transparent" }
27
- };
36
+ const lodashEs = require("lodash-es");
37
+ const vueRouter = require("vue-router");
38
+ const Menu_vue_vue_type_script_setup_true_lang = require("../menu/Menu.vue.js");
39
+ ;/* empty css */
40
+ const Tabs_vue_vue_type_script_setup_true_lang = require("../tabs/Tabs.vue.js");
41
+ ;/* empty css */
42
+ const useTabsStore = require("../tabs/useTabsStore.js");
43
+ const _hoisted_1 = { class: "w-full flex justify-center" };
44
+ const _hoisted_2 = { class: "flex flex-1 min-h-0 overflow-hidden gap-3" };
28
45
  const _sfc_main = /* @__PURE__ */ vue.defineComponent(__spreadProps(__spreadValues({}, {
29
46
  name: "JkyPageLayout"
30
47
  }), {
31
48
  __name: "PageLayout",
32
49
  props: {
50
+ showTopMenu: { type: Boolean, default: true },
51
+ showSideMenu: { type: Boolean, default: true },
52
+ asideWidth: { default: "200px" },
33
53
  asideClass: {},
34
54
  asideWithScrollbar: { type: Boolean, default: true },
35
55
  mainClass: {},
36
- mainWithCard: { type: Boolean },
56
+ mainWithCard: { type: Boolean, default: false },
37
57
  mainWithScrollbar: { type: Boolean, default: false },
38
58
  contentClass: {},
39
- navigationClass: {},
40
- navigationWithScrollbar: { type: Boolean, default: true },
41
- showNavigation: { type: Boolean, default: true },
42
- headerClass: {},
43
- tabsClass: {},
44
- showDashboard: { type: Boolean },
45
- dashboardWithScrollbar: { type: Boolean },
46
- dashboardClass: {},
47
- className: {}
59
+ cachable: { type: Boolean, default: true },
60
+ transitionName: { default: "fade" },
61
+ className: {},
62
+ tabsWithCard: { type: Boolean, default: true },
63
+ cardPadding: { default: "0px" },
64
+ topLevels: {},
65
+ sideLevels: {},
66
+ topMenuTrigger: { default: "click" },
67
+ topMenuSingleLevel: { type: Boolean, default: true }
48
68
  },
49
69
  setup(__props) {
50
70
  const props = __props;
71
+ const router = vueRouter.useRouter();
72
+ const route = vueRouter.useRoute();
73
+ const store = useTabsStore.useTabsStore();
74
+ const attrs = vue.useAttrs();
75
+ const activeTopMenu = vue.ref("");
76
+ const activeSideMenu = vue.ref("");
77
+ const routes = router.getRoutes();
78
+ const cacheInclude = vue.computed(() => store.getCacheTabs());
79
+ vue.watch(
80
+ cacheInclude,
81
+ (cacheTabs) => {
82
+ console.warn("CacheTabs changed:", cacheTabs);
83
+ },
84
+ { deep: true }
85
+ );
86
+ function buildMenuFromRoutes(routes2) {
87
+ const menuRoutes = routes2.filter((r) => {
88
+ var _a;
89
+ return (_a = r.meta) == null ? void 0 : _a.title;
90
+ });
91
+ const buildMenuItem = (route2, parentPath = "") => {
92
+ var _a, _b;
93
+ const fullPath = parentPath ? `${parentPath}/${route2.path}` : route2.path;
94
+ const normalizedPath = fullPath.startsWith("/") ? fullPath : `/${fullPath}`;
95
+ const item = {
96
+ index: normalizedPath,
97
+ title: ((_a = route2.meta) == null ? void 0 : _a.title) || "",
98
+ icon: ((_b = route2.meta) == null ? void 0 : _b.icon) || "",
99
+ route: normalizedPath,
100
+ path: normalizedPath,
101
+ customClass: activeTopMenu.value.startsWith(normalizedPath) ? "is-active jky-page-layout__active-top-menu" : ""
102
+ };
103
+ if (route2.children && route2.children.length > 0) {
104
+ item.children = route2.children.filter((child) => {
105
+ var _a2;
106
+ return (_a2 = child.meta) == null ? void 0 : _a2.title;
107
+ }).map((child) => buildMenuItem(child, normalizedPath));
108
+ }
109
+ return item;
110
+ };
111
+ return menuRoutes.filter((route2) => {
112
+ const pathSegments = route2.path.split("/").filter(Boolean);
113
+ return pathSegments.length === 1;
114
+ }).map((route2) => buildMenuItem(route2));
115
+ }
116
+ const menuData = vue.computed(() => {
117
+ return buildMenuFromRoutes(routes);
118
+ });
119
+ const topMenuData = vue.computed(() => {
120
+ console.warn("topMenuData:", menuData.value, props, attrs);
121
+ if (props.topMenuSingleLevel) {
122
+ return lodashEs.cloneDeep(menuData.value).map((item) => {
123
+ const _a = item, { children } = _a, rest = __objRest(_a, ["children"]);
124
+ return rest;
125
+ });
126
+ }
127
+ return menuData.value;
128
+ });
129
+ const displayedSideMenu = vue.computed(() => {
130
+ if (menuData.value.length === 0) {
131
+ console.warn("displayedSideMenu: menuData is empty");
132
+ return [];
133
+ }
134
+ const topMenuItem = route.matched[0];
135
+ if (!topMenuItem) {
136
+ console.warn("displayedSideMenu: topMenuItem is empty");
137
+ return [];
138
+ }
139
+ const found = menuData.value.find((item) => item.path === topMenuItem.path);
140
+ if (!found) {
141
+ console.warn("displayedSideMenu: found not found", topMenuItem);
142
+ return [];
143
+ }
144
+ if ((found == null ? void 0 : found.children) && found.children.length > 0) {
145
+ return found.children;
146
+ }
147
+ return [];
148
+ });
149
+ const computedAsideWidth = vue.computed(() => {
150
+ if (props.showSideMenu && displayedSideMenu.value.length > 0) {
151
+ return props.asideWidth;
152
+ }
153
+ return "0";
154
+ });
155
+ vue.watch(
156
+ () => route.path,
157
+ () => {
158
+ const routePath = route.path;
159
+ const matchedMenus = route.matched.filter((r) => {
160
+ var _a;
161
+ return (_a = r.meta) == null ? void 0 : _a.title;
162
+ });
163
+ if (matchedMenus.length === 0) {
164
+ console.warn("No matching menu item found for route:", routePath);
165
+ return;
166
+ }
167
+ activeSideMenu.value = routePath;
168
+ if (matchedMenus.length >= 2) {
169
+ activeTopMenu.value = matchedMenus[matchedMenus.length - 2].path;
170
+ } else {
171
+ activeTopMenu.value = matchedMenus[0].path;
172
+ }
173
+ console.warn("Updated menu:", {
174
+ activeTopMenu: activeTopMenu.value,
175
+ activeSideMenu: activeSideMenu.value
176
+ });
177
+ },
178
+ { immediate: true }
179
+ );
180
+ function handleMenuOpen(index) {
181
+ console.warn("handleMenuOpen called with index:", index);
182
+ }
183
+ function handleMenuSelect(index) {
184
+ router.push(index);
185
+ }
51
186
  return (_ctx, _cache) => {
52
- const _component_ElAutoResizer = vue.resolveComponent("ElAutoResizer");
53
- return vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [
54
- vue.createVNode(vue.unref(ElementPlus.ElCard), {
55
- class: vue.normalizeClass(["jky-page-layout__aside shrink-0 overflow-hidden p-0", props.asideClass]),
56
- style: { "--el-card-padding": 0 }
57
- }, vue.createSlots({
58
- default: vue.withCtx(() => [
59
- props.asideWithScrollbar ? (vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElScrollbar), { key: 0 }, {
60
- default: vue.withCtx(() => [
61
- vue.renderSlot(_ctx.$slots, "aside")
62
- ]),
63
- _: 3
64
- })) : vue.renderSlot(_ctx.$slots, "aside", { key: 1 })
65
- ]),
66
- _: 2
67
- }, [
68
- _ctx.$slots.menuHeader ? {
69
- name: "header",
70
- fn: vue.withCtx(() => [
71
- vue.renderSlot(_ctx.$slots, "menuHeader")
72
- ]),
73
- key: "0"
74
- } : void 0
75
- ]), 1032, ["class"]),
76
- __props.showNavigation ? (vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElCard), {
187
+ return vue.openBlock(), vue.createElementBlock("div", {
188
+ class: vue.normalizeClass(["jky-page-layout flex h-full w-full flex-col overflow-hidden gap-3", props.className])
189
+ }, [
190
+ props.showTopMenu && menuData.value.length > 0 ? (vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElCard), {
77
191
  key: 0,
78
- class: vue.normalizeClass(["jky-page-layout__navigation shrink-0 overflow-hidden p-0", props.navigationClass]),
192
+ class: "jky-page-layout__top-menu shrink-0 overflow-hidden p-0",
79
193
  style: { "--el-card-padding": 0 }
80
- }, vue.createSlots({
194
+ }, {
81
195
  default: vue.withCtx(() => [
82
- props.navigationWithScrollbar ? (vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElScrollbar), { key: 0 }, {
83
- default: vue.withCtx(() => [
84
- vue.renderSlot(_ctx.$slots, "navigation")
85
- ]),
86
- _: 3
87
- })) : vue.renderSlot(_ctx.$slots, "navigation", { key: 1 })
196
+ vue.createElementVNode("div", _hoisted_1, [
197
+ vue.createVNode(Menu_vue_vue_type_script_setup_true_lang.default, {
198
+ mode: "horizontal",
199
+ "default-active": activeTopMenu.value,
200
+ "menu-data": topMenuData.value,
201
+ "menu-trigger": props.topMenuTrigger,
202
+ router: false,
203
+ levels: props.topLevels,
204
+ onSelect: handleMenuSelect,
205
+ onOpen: handleMenuOpen
206
+ }, null, 8, ["default-active", "menu-data", "menu-trigger", "levels"])
207
+ ])
88
208
  ]),
89
- _: 2
90
- }, [
91
- _ctx.$slots.navigationHeader ? {
92
- name: "header",
93
- fn: vue.withCtx(() => [
94
- vue.renderSlot(_ctx.$slots, "navigationHeader")
95
- ]),
96
- key: "0"
97
- } : void 0
98
- ]), 1032, ["class"])) : vue.createCommentVNode("", true),
99
- vue.createElementVNode("div", {
100
- class: vue.normalizeClass(["jky-page-layout__main flex-1 flex flex-col min-w-0 overflow-hidden p-0 gap-y-4", props.mainClass])
101
- }, [
102
- _ctx.$slots.header ? (vue.openBlock(), vue.createElementBlock("div", {
103
- key: 0,
104
- class: vue.normalizeClass(["jky-page-layout__header shrink-0 flex items-center overflow-hidden px-4", props.headerClass])
105
- }, [
106
- vue.renderSlot(_ctx.$slots, "header")
107
- ], 2)) : vue.createCommentVNode("", true),
108
- _ctx.$slots.tabs ? (vue.openBlock(), vue.createElementBlock("div", {
109
- key: 1,
110
- class: vue.normalizeClass(["jky-page-layout__tabs shrink-0 overflow-hidden", props.tabsClass])
111
- }, [
112
- vue.renderSlot(_ctx.$slots, "tabs")
113
- ], 2)) : vue.createCommentVNode("", true),
114
- _ctx.$slots.dashboard ? (vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElCard), {
115
- key: 2,
116
- class: vue.normalizeClass(["jky-page-layout__dashboard shrink-0 overflow-hidden", props.dashboardClass])
117
- }, {
118
- default: vue.withCtx(() => [
119
- props.dashboardWithScrollbar ? (vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElScrollbar), { key: 0 }, {
120
- default: vue.withCtx(() => [
121
- vue.renderSlot(_ctx.$slots, "dashboard")
122
- ]),
123
- _: 3
124
- })) : vue.renderSlot(_ctx.$slots, "dashboard", { key: 1 })
125
- ]),
126
- _: 3
127
- }, 8, ["class"])) : vue.createCommentVNode("", true),
128
- (vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(props.mainWithCard ? vue.unref(ElementPlus.ElCard) : "div"), {
129
- "body-class": props.mainWithScrollbar ? "" : "pb-0!",
130
- class: vue.normalizeClass(["jky-page-layout__content flex-1 min-h-0 overflow-hidden", props.contentClass])
209
+ _: 1
210
+ })) : vue.createCommentVNode("", true),
211
+ vue.createElementVNode("div", _hoisted_2, [
212
+ vue.createVNode(vue.unref(ElementPlus.ElAside), {
213
+ class: "shrink-0 overflow-hidden h-full",
214
+ style: vue.normalizeStyle({ "--el-aside-width": computedAsideWidth.value })
131
215
  }, {
132
216
  default: vue.withCtx(() => [
133
- props.mainWithScrollbar ? (vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElScrollbar), { key: 0 }, {
217
+ props.showSideMenu && displayedSideMenu.value.length > 0 ? (vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElCard), {
218
+ key: 0,
219
+ class: "h-full",
220
+ style: vue.normalizeStyle({ "--el-card-padding": props.cardPadding })
221
+ }, {
134
222
  default: vue.withCtx(() => [
135
- vue.renderSlot(_ctx.$slots, "default")
136
- ]),
137
- _: 3
138
- })) : (vue.openBlock(), vue.createBlock(_component_ElAutoResizer, { key: 1 }, {
139
- default: vue.withCtx(({ height }) => [
140
- vue.renderSlot(_ctx.$slots, "default", { height })
223
+ props.asideWithScrollbar ? (vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElScrollbar), { key: 0 }, {
224
+ default: vue.withCtx(() => [
225
+ vue.createVNode(Menu_vue_vue_type_script_setup_true_lang.default, {
226
+ mode: "vertical",
227
+ "default-active": activeSideMenu.value,
228
+ "menu-data": displayedSideMenu.value,
229
+ onSelect: handleMenuSelect
230
+ }, null, 8, ["default-active", "menu-data"])
231
+ ]),
232
+ _: 1
233
+ })) : vue.createCommentVNode("", true),
234
+ vue.createVNode(Menu_vue_vue_type_script_setup_true_lang.default, {
235
+ mode: "vertical",
236
+ "default-active": activeSideMenu.value,
237
+ "menu-data": displayedSideMenu.value,
238
+ onSelect: handleMenuSelect
239
+ }, null, 8, ["default-active", "menu-data"])
141
240
  ]),
142
- _: 3
143
- }))
241
+ _: 1
242
+ }, 8, ["style"])) : vue.createCommentVNode("", true)
144
243
  ]),
145
- _: 3
146
- }, 8, ["body-class", "class"]))
147
- ], 2)
148
- ]);
244
+ _: 1
245
+ }, 8, ["style"]),
246
+ vue.createElementVNode("div", {
247
+ class: vue.normalizeClass(["jky-page-layout__main flex-1 flex flex-col min-w-0 overflow-hidden", props.mainClass])
248
+ }, [
249
+ props.tabsWithCard ? (vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElCard), {
250
+ key: 0,
251
+ class: "jky-page-layout__tabs shrink-0",
252
+ style: vue.normalizeStyle({ "--el-card-padding": props.cardPadding })
253
+ }, {
254
+ default: vue.withCtx(() => [
255
+ vue.createVNode(Tabs_vue_vue_type_script_setup_true_lang.default, {
256
+ mode: "route",
257
+ cachable: props.cachable
258
+ }, null, 8, ["cachable"])
259
+ ]),
260
+ _: 1
261
+ }, 8, ["style"])) : (vue.openBlock(), vue.createBlock(Tabs_vue_vue_type_script_setup_true_lang.default, {
262
+ key: 1,
263
+ class: "jky-page-layout__tabs shrink-0",
264
+ mode: "route",
265
+ cachable: props.cachable
266
+ }, null, 8, ["cachable"])),
267
+ (vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(props.mainWithCard ? vue.unref(ElementPlus.ElCard) : "div"), {
268
+ class: vue.normalizeClass(["jky-page-layout__content flex-1 min-h-0 overflow-hidden", props.contentClass]),
269
+ "body-class": props.mainWithScrollbar ? "" : "pb-0!"
270
+ }, {
271
+ default: vue.withCtx(() => [
272
+ props.mainWithScrollbar ? (vue.openBlock(), vue.createBlock(vue.unref(ElementPlus.ElScrollbar), { key: 0 }, {
273
+ default: vue.withCtx(() => [
274
+ vue.createVNode(vue.unref(vueRouter.RouterView), null, {
275
+ default: vue.withCtx(({ Component, route: currentRoute }) => [
276
+ vue.createVNode(vue.Transition, {
277
+ name: props.transitionName
278
+ }, {
279
+ default: vue.withCtx(() => [
280
+ (vue.openBlock(), vue.createBlock(vue.KeepAlive, {
281
+ include: props.cachable ? cacheInclude.value : []
282
+ }, [
283
+ (vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(Component), {
284
+ key: currentRoute.name
285
+ }))
286
+ ], 1032, ["include"]))
287
+ ]),
288
+ _: 2
289
+ }, 1032, ["name"])
290
+ ]),
291
+ _: 1
292
+ })
293
+ ]),
294
+ _: 1
295
+ })) : (vue.openBlock(), vue.createBlock(vue.unref(vueRouter.RouterView), { key: 1 }, {
296
+ default: vue.withCtx(({ Component, route: currentRoute }) => [
297
+ vue.createVNode(vue.Transition, {
298
+ name: props.transitionName
299
+ }, {
300
+ default: vue.withCtx(() => [
301
+ (vue.openBlock(), vue.createBlock(vue.KeepAlive, {
302
+ include: props.cachable ? cacheInclude.value : []
303
+ }, [
304
+ (vue.openBlock(), vue.createBlock(vue.resolveDynamicComponent(Component), {
305
+ key: currentRoute.name
306
+ }))
307
+ ], 1032, ["include"]))
308
+ ]),
309
+ _: 2
310
+ }, 1032, ["name"])
311
+ ]),
312
+ _: 1
313
+ }))
314
+ ]),
315
+ _: 1
316
+ }, 8, ["class", "body-class"]))
317
+ ], 2)
318
+ ])
319
+ ], 2);
149
320
  };
150
321
  }
151
322
  }));
@@ -7,4 +7,63 @@
7
7
  .el-menu {
8
8
  border-right: none;
9
9
  }
10
+
11
+ /* 顶部激活菜单项的自定义样式 */
12
+ .jky-page-layout__active-top-menu {
13
+ /* 这里可以添加自定义样式,例如: */
14
+ /* background-color: var(--el-color-primary-light-9); */
15
+ /* color: var(--el-color-primary); */
16
+ }
17
+ }
18
+
19
+ /* 淡入淡出动画 */
20
+ .fade-enter-active,
21
+ .fade-leave-active {
22
+ transition: opacity 0.3s ease;
23
+ }
24
+ .fade-enter-from,
25
+ .fade-leave-to {
26
+ opacity: 0;
27
+ }
28
+
29
+ /* 缩放动画 */
30
+ .zoom-enter-active,
31
+ .zoom-leave-active {
32
+ transition:
33
+ opacity 0.3s ease,
34
+ transform 0.3s ease;
35
+ }
36
+ .zoom-enter-from {
37
+ opacity: 0;
38
+ transform: scale(0.95);
39
+ }
40
+ .zoom-leave-to {
41
+ opacity: 0;
42
+ transform: scale(1.05);
43
+ }
44
+
45
+ /* 滑动动画 */
46
+ .slide-left-enter-active,
47
+ .slide-left-leave-active,
48
+ .slide-right-enter-active,
49
+ .slide-right-leave-active {
50
+ transition:
51
+ opacity 0.3s ease,
52
+ transform 0.3s ease;
53
+ }
54
+ .slide-left-enter-from {
55
+ opacity: 0;
56
+ transform: translateX(-30px);
57
+ }
58
+ .slide-left-leave-to {
59
+ opacity: 0;
60
+ transform: translateX(30px);
61
+ }
62
+ .slide-right-enter-from {
63
+ opacity: 0;
64
+ transform: translateX(30px);
65
+ }
66
+ .slide-right-leave-to {
67
+ opacity: 0;
68
+ transform: translateX(-30px);
10
69
  }