@peng_kai/kit 0.0.14 → 0.0.16

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 (91) hide show
  1. package/.vscode/settings.json +41 -0
  2. package/admin/components/filter/index.ts +5 -0
  3. package/admin/{filter → components/filter/src}/FilterDrawer.vue +99 -96
  4. package/admin/{filter → components/filter/src}/FilterParam.vue +76 -76
  5. package/admin/{filter → components/filter/src}/FilterReset.vue +7 -4
  6. package/admin/{filter → components/filter/src}/useFilterParams.ts +9 -9
  7. package/admin/{filter → components/filter/src}/useFilterQuery.ts +11 -11
  8. package/admin/components/scroll-nav/index.ts +1 -1
  9. package/admin/components/scroll-nav/src/ScrollNav.vue +59 -59
  10. package/admin/components/text/index.ts +13 -13
  11. package/admin/components/text/src/Amount.vue +117 -114
  12. package/admin/components/text/src/Datetime.vue +44 -44
  13. package/admin/components/text/src/Duration.vue +26 -26
  14. package/admin/components/text/src/Hash.vue +42 -40
  15. package/admin/components/text/src/createTagGetter.ts +13 -13
  16. package/admin/defines/index.ts +4 -5
  17. package/admin/defines/page/definePage.ts +12 -0
  18. package/admin/defines/page/index.ts +1 -0
  19. package/admin/defines/route/defineRoute.ts +14 -0
  20. package/admin/defines/route/getRoutes.ts +84 -0
  21. package/admin/defines/route/helpers.ts +49 -0
  22. package/admin/defines/route/index.ts +73 -0
  23. package/admin/defines/route-guard/defineRouteGuard.ts +18 -0
  24. package/admin/defines/route-guard/getRouteGuards.ts +40 -0
  25. package/admin/defines/route-guard/index.ts +2 -0
  26. package/admin/defines/startup/defineStartup.ts +11 -0
  27. package/admin/defines/startup/getStartups.ts +30 -0
  28. package/admin/defines/startup/index.ts +2 -0
  29. package/admin/hooks/index.ts +5 -6
  30. package/admin/hooks/useMenu.ts +128 -128
  31. package/admin/hooks/usePage.ts +141 -139
  32. package/admin/hooks/usePageTab.ts +35 -35
  33. package/admin/layout/large/Breadcrumb.vue +69 -70
  34. package/admin/layout/large/Content.vue +24 -24
  35. package/admin/layout/large/Menu.vue +69 -68
  36. package/admin/layout/large/PageTab.vue +71 -71
  37. package/admin/layout/large/index.ts +4 -4
  38. package/admin/permission/index.ts +4 -0
  39. package/admin/permission/routerGuard.ts +43 -0
  40. package/admin/permission/usePermission.ts +52 -0
  41. package/admin/permission/vuePlugin.ts +30 -0
  42. package/admin/route-guards/index.ts +2 -0
  43. package/admin/route-guards/pageProgress.ts +16 -0
  44. package/admin/route-guards/pageTitle.ts +24 -0
  45. package/admin/styles/globalCover.scss +43 -43
  46. package/admin/types/assist.ts +10 -0
  47. package/admin/unocss/index.ts +1 -1
  48. package/antd/components/InputNumberRange.vue +53 -47
  49. package/antd/directives/formLabelAlign.ts +36 -31
  50. package/antd/hooks/createAntdModal.ts +29 -29
  51. package/antd/hooks/useAntdDrawer.ts +73 -73
  52. package/antd/hooks/useAntdForm.helpers.ts +18 -18
  53. package/antd/hooks/useAntdForm.ts +38 -37
  54. package/antd/hooks/useAntdModal.ts +25 -25
  55. package/antd/hooks/useAntdTable.ts +70 -70
  56. package/antd/hooks/useAntdTheme.ts +86 -0
  57. package/antd/index.ts +8 -7
  58. package/eslint.config.js +50 -0
  59. package/kitDependencies.ts +21 -7
  60. package/package.json +46 -40
  61. package/pnpm-lock.yaml +2689 -0
  62. package/request/helpers.ts +49 -32
  63. package/request/index.ts +2 -2
  64. package/request/interceptors/checkCode.ts +8 -8
  65. package/request/interceptors/filterEmptyValue.ts +9 -9
  66. package/request/interceptors/formatPaging.ts +12 -12
  67. package/request/interceptors/index.ts +7 -6
  68. package/request/interceptors/popupMessage.ts +35 -35
  69. package/request/interceptors/returnResultType.ts +19 -19
  70. package/request/interceptors/toLogin.ts +13 -0
  71. package/request/interceptors/unitizeAxiosError.ts +7 -7
  72. package/request/queryClient.ts +42 -0
  73. package/request/request.ts +21 -21
  74. package/request/type.d.ts +89 -89
  75. package/tsconfig.json +47 -18
  76. package/utils/index.ts +67 -29
  77. package/vue/components/index.ts +1 -0
  78. package/{components → vue/components}/infinite-query/index.ts +1 -1
  79. package/{components → vue/components}/infinite-query/src/InfiniteQuery.vue +147 -147
  80. package/{components → vue/components}/infinite-query/src/useCreateTrigger.ts +35 -35
  81. package/vue/hooks/useComponentRef.ts +12 -12
  82. package/vue/hooks/useIsMounted.ts +4 -4
  83. package/vue/hooks/useTeleportTarget.ts +7 -7
  84. package/vue/index.ts +4 -3
  85. package/admin/defines/definePage.ts +0 -14
  86. package/admin/defines/defineRoute.helpers.ts +0 -30
  87. package/admin/defines/defineRoute.ts +0 -161
  88. package/admin/defines/defineRouteGuard.ts +0 -56
  89. package/admin/defines/defineStartup.ts +0 -41
  90. package/admin/filter/index.ts +0 -5
  91. package/admin/hooks/usePermission.ts +0 -5
@@ -0,0 +1,41 @@
1
+ {
2
+ // Enable the ESlint flat config support
3
+ "eslint.experimental.useFlatConfig": true,
4
+
5
+ // Disable the default formatter, use eslint instead
6
+ "prettier.enable": false,
7
+ "editor.formatOnSave": false,
8
+
9
+ // Auto fix
10
+ "editor.codeActionsOnSave": {
11
+ "source.fixAll.eslint": "explicit",
12
+ "source.organizeImports": "never"
13
+ },
14
+
15
+ // Silent the stylistic rules in you IDE, but still auto fix them
16
+ "eslint.rules.customizations": [
17
+ { "rule": "style/*", "severity": "off" },
18
+ { "rule": "*-indent", "severity": "off" },
19
+ { "rule": "*-spacing", "severity": "off" },
20
+ { "rule": "*-spaces", "severity": "off" },
21
+ { "rule": "*-order", "severity": "off" },
22
+ { "rule": "*-dangle", "severity": "off" },
23
+ { "rule": "*-newline", "severity": "off" },
24
+ { "rule": "*quotes", "severity": "off" },
25
+ { "rule": "*semi", "severity": "off" }
26
+ ],
27
+
28
+ // Enable eslint for all supported languages
29
+ "eslint.validate": [
30
+ "javascript",
31
+ "javascriptreact",
32
+ "typescript",
33
+ "typescriptreact",
34
+ "vue",
35
+ "html",
36
+ "markdown",
37
+ "json",
38
+ "jsonc",
39
+ "yaml"
40
+ ]
41
+ }
@@ -0,0 +1,5 @@
1
+ export { default as FilterDrawer } from './src/FilterDrawer.vue';
2
+ export { default as FilterReset } from './src/FilterReset.vue';
3
+ export { default as FilterParam, paramTypes } from './src/FilterParam.vue';
4
+ export { useFilterParams } from './src/useFilterParams';
5
+ export { useFilterInfiniteQuery, useFilterPaginationQuery } from './src/useFilterQuery';
@@ -1,96 +1,99 @@
1
- <script lang="ts" setup>
2
- import { ref } from "vue";
3
- import { Drawer as ADrawer, Button as AButton } from "ant-design-vue";
4
-
5
- const emits = defineEmits<{
6
- (e: 'filter'): void
7
- (e: 'reset', value: number): void
8
- }>()
9
- const filterVisible = ref(false)
10
-
11
- function filter() {
12
- emits('filter')
13
- filterVisible.value = false
14
- }
15
-
16
- function reset() {
17
- emits('reset', 1)
18
- filterVisible.value = false
19
- }
20
- </script>
21
-
22
- <template>
23
- <div class="p-3 mb-2 bg-white text-14px" @click="filterVisible = true">
24
- <!-- .filter-params 为空时显示 .filter-params-tips -->
25
- <div class="filter-params">
26
- <slot name="params" />
27
- </div>
28
- <div class="filter-params-tips">
29
- 条件筛选,点击打开
30
- </div>
31
- </div>
32
-
33
- <ADrawer v-model:open="filterVisible" class="filter-drawer" placement="bottom" height="50vh">
34
- <template #extra>
35
- <AButton class="mr-3 my--3" @click="reset()">
36
- 重置
37
- </AButton>
38
- <AButton class="my--3" type="primary" @click="filter()">
39
- 筛选
40
- </AButton>
41
- </template>
42
- <template #default>
43
- <slot />
44
- </template>
45
- </ADrawer>
46
- </template>
47
-
48
- <style scoped lang="scss">
49
- .filter-params {
50
- display: flex;
51
- flex-wrap: wrap;
52
- justify-content: flex-start;
53
- gap: 5px 15px;
54
- }
55
-
56
- // .filter-params 为空时显示 .filter-params-tips
57
- .filter-params-tips {
58
- display: none;
59
- color: theme('colors.gray.DEFAULT');
60
- }
61
-
62
- .filter-params:empty {
63
- display: none;
64
- }
65
-
66
- .filter-params:empty + .filter-params-tips {
67
- display: block;
68
- }
69
- </style>
70
-
71
- <style lang="scss">
72
- .filter-drawer {
73
- .ant-drawer-header {
74
- padding: 16px;
75
-
76
- .ant-drawer-close {
77
- --expand: 5px;
78
-
79
- padding: var(--expand);
80
- margin: calc(var(--expand) * -1) var(--expand) calc(var(--expand) * -1) 0;
81
- }
82
- }
83
-
84
- .ant-drawer-body {
85
- padding: 16px;
86
- }
87
-
88
- .ant-form-item {
89
- margin-bottom: 0;
90
-
91
- .ant-form-item-label {
92
- padding-bottom: 0;
93
- }
94
- }
95
- }
96
- </style>
1
+ <script lang="ts" setup>
2
+ import { ref } from 'vue';
3
+ import { Button as AButton, Drawer as ADrawer } from 'ant-design-vue';
4
+
5
+ const emits = defineEmits<{
6
+ (e: 'filter'): void
7
+ (e: 'reset', value: number): void
8
+ }>();
9
+ const filterVisible = ref(false);
10
+
11
+ function filter() {
12
+ emits('filter');
13
+ filterVisible.value = false;
14
+ }
15
+
16
+ function reset() {
17
+ emits('reset', 1);
18
+ filterVisible.value = false;
19
+ }
20
+ </script>
21
+
22
+ <template>
23
+ <div class="p-3 mb-2 bg-white text-14px" @click="filterVisible = true">
24
+ <!-- .filter-params 为空时显示 .filter-params-tips -->
25
+ <div class="filter-params">
26
+ <slot name="params" />
27
+ </div>
28
+ <div class="filter-params-tips">
29
+ 条件筛选,点击打开
30
+ </div>
31
+ </div>
32
+
33
+ <ADrawer
34
+ v-model:open="filterVisible" class="filter-drawer" placement="bottom"
35
+ height="50vh"
36
+ >
37
+ <template #extra>
38
+ <AButton class="mr-3 my--3" @click="reset()">
39
+ 重置
40
+ </AButton>
41
+ <AButton class="my--3" type="primary" @click="filter()">
42
+ 筛选
43
+ </AButton>
44
+ </template>
45
+ <template #default>
46
+ <slot />
47
+ </template>
48
+ </ADrawer>
49
+ </template>
50
+
51
+ <style scoped lang="scss">
52
+ .filter-params {
53
+ display: flex;
54
+ flex-wrap: wrap;
55
+ justify-content: flex-start;
56
+ gap: 5px 15px;
57
+ }
58
+
59
+ // .filter-params 为空时显示 .filter-params-tips
60
+ .filter-params-tips {
61
+ display: none;
62
+ color: theme('colors.gray.DEFAULT');
63
+ }
64
+
65
+ .filter-params:empty {
66
+ display: none;
67
+ }
68
+
69
+ .filter-params:empty + .filter-params-tips {
70
+ display: block;
71
+ }
72
+ </style>
73
+
74
+ <style lang="scss">
75
+ .filter-drawer {
76
+ .ant-drawer-header {
77
+ padding: 16px;
78
+
79
+ .ant-drawer-close {
80
+ --expand: 5px;
81
+
82
+ padding: var(--expand);
83
+ margin: calc(var(--expand) * -1) var(--expand) calc(var(--expand) * -1) 0;
84
+ }
85
+ }
86
+
87
+ .ant-drawer-body {
88
+ padding: 16px;
89
+ }
90
+
91
+ .ant-form-item {
92
+ margin-bottom: 0;
93
+
94
+ .ant-form-item-label {
95
+ padding-bottom: 0;
96
+ }
97
+ }
98
+ }
99
+ </style>
@@ -1,76 +1,76 @@
1
- <script lang="ts">
2
- import isNil from 'lodash-es/isNil'
3
- import isFinite from 'lodash-es/isFinite'
4
- import dayjs from 'dayjs'
5
- import bignumber from 'bignumber.js'
6
-
7
- export const paramTypes = { numberRange, datetimeRange, options }
8
-
9
- /**
10
- * 时间范围格式化
11
- * @param range 数字范围
12
- * @param unit 单位
13
- */
14
- function numberRange(range?: [number, number], unit?: string) {
15
- if (!range?.every(isFinite))
16
- return ''
17
-
18
- return `${bignumber(range[0]).toFormat()}~${bignumber(range[1]).toFormat()}${unit}`
19
- }
20
-
21
- /**
22
- * 时间范围格式化
23
- * @param range 时间范围
24
- * @param template 格式化模板(文档:https://dayjs.gitee.io/docs/zh-CN/display/format )
25
- */
26
- function datetimeRange(range?: [string | dayjs.Dayjs, string | dayjs.Dayjs], template = 'YYYY-MM-DD') {
27
- if (!range?.every(v => dayjs(v).isValid()))
28
- return ''
29
-
30
- return `${dayjs(range[0]).format(template)} ~ ${dayjs(range[1]).format(template)}`
31
- }
32
-
33
- function options(
34
- value?: string | number | Array<string | number>,
35
- options?: Array<{ value: string | number; label: any }>,
36
- ) {
37
- if (isNil(value) || isNil(options))
38
- return
39
- if (value === '')
40
- return
41
-
42
- const _value = Array.isArray(value) ? value : [value]
43
-
44
- return options
45
- .filter(o => _value.includes(o.value))
46
- .map(o => o.label)
47
- .join(', ')
48
- }
49
- </script>
50
-
51
- <script setup lang="ts">
52
- const props = defineProps<{
53
- label: string
54
- content?: any
55
- }>()
56
- </script>
57
-
58
- <template>
59
- <div v-if="props.content" class="item-param">
60
- <span class="label">{{ props.label }}</span>
61
- <span class="content">{{ props.content }}</span>
62
- </div>
63
- </template>
64
-
65
- <style lang="scss" scoped>
66
- .label {
67
- display: inline-block;
68
- margin-right: 0.3em;
69
- color: theme('colors.gray.DEFAULT');
70
- }
71
-
72
- .content {
73
- color: theme('colors.primary.DEFAULT');
74
- word-break: break-all;
75
- }
76
- </style>
1
+ <script lang="ts">
2
+ import isNil from 'lodash-es/isNil';
3
+ import isFinite from 'lodash-es/isFinite';
4
+ import dayjs from 'dayjs';
5
+ import bignumber from 'bignumber.js';
6
+
7
+ export const paramTypes = { numberRange, datetimeRange, options };
8
+
9
+ /**
10
+ * 时间范围格式化
11
+ * @param range 数字范围
12
+ * @param unit 单位
13
+ */
14
+ function numberRange(range?: [number, number], unit?: string) {
15
+ if (!range?.every(isFinite))
16
+ return '';
17
+
18
+ return `${bignumber(range[0]).toFormat()}~${bignumber(range[1]).toFormat()}${unit}`;
19
+ }
20
+
21
+ /**
22
+ * 时间范围格式化
23
+ * @param range 时间范围
24
+ * @param template 格式化模板(文档:https://dayjs.gitee.io/docs/zh-CN/display/format )
25
+ */
26
+ function datetimeRange(range?: [string | dayjs.Dayjs, string | dayjs.Dayjs], template = 'YYYY-MM-DD') {
27
+ if (!range?.every(v => dayjs(v).isValid()))
28
+ return '';
29
+
30
+ return `${dayjs(range[0]).format(template)} ~ ${dayjs(range[1]).format(template)}`;
31
+ }
32
+
33
+ function options(
34
+ value?: string | number | Array<string | number>,
35
+ options?: Array<{ value: string | number, label: any }>,
36
+ ) {
37
+ if (isNil(value) || isNil(options))
38
+ return;
39
+ if (value === '')
40
+ return;
41
+
42
+ const _value = Array.isArray(value) ? value : [value];
43
+
44
+ return options
45
+ .filter(o => _value.includes(o.value))
46
+ .map(o => o.label)
47
+ .join(', ');
48
+ }
49
+ </script>
50
+
51
+ <script setup lang="ts">
52
+ const props = defineProps<{
53
+ label: string
54
+ content?: any
55
+ }>();
56
+ </script>
57
+
58
+ <template>
59
+ <div v-if="props.content" class="item-param">
60
+ <span class="label">{{ props.label }}</span>
61
+ <span class="content">{{ props.content }}</span>
62
+ </div>
63
+ </template>
64
+
65
+ <style lang="scss" scoped>
66
+ .label {
67
+ display: inline-block;
68
+ margin-right: 0.3em;
69
+ color: theme('colors.gray.DEFAULT');
70
+ }
71
+
72
+ .content {
73
+ color: theme('colors.primary.DEFAULT');
74
+ word-break: break-all;
75
+ }
76
+ </style>
@@ -1,18 +1,21 @@
1
1
  <script setup lang="ts">
2
- import { Button as AButton } from "ant-design-vue";
2
+ import { Button as AButton } from 'ant-design-vue';
3
3
 
4
4
  const props = defineProps<{
5
5
  loading?: boolean
6
- }>()
6
+ }>();
7
7
  const emits = defineEmits<{
8
8
  (e: 'filter'): void
9
9
  (e: 'reset'): void
10
- }>()
10
+ }>();
11
11
  </script>
12
12
 
13
13
  <template>
14
14
  <div class="flex-none flex w-min ml-auto">
15
- <AButton class="mr-2 filter-btn" type="primary" htmlType="submit" :loading="props.loading" @click="emits('filter')">
15
+ <AButton
16
+ class="mr-2 filter-btn" type="primary" htmlType="submit"
17
+ :loading="props.loading" @click="emits('filter')"
18
+ >
16
19
  查询
17
20
  </AButton>
18
21
  <AButton :disabled="props.loading" @click="emits('reset')">
@@ -1,19 +1,19 @@
1
- import { extendRef } from '@vueuse/core'
2
- import { reactive } from "vue";
1
+ import { extendRef } from '@vueuse/core';
2
+ import { reactive } from 'vue';
3
3
 
4
- type PageParams = { page?: string | number; page_size?: string | number }
5
- const defaultPageParams: PageParams = { page: 1, page_size: 10 }
4
+ interface PageParams { page?: string | number, page_size?: string | number };
5
+ const defaultPageParams: PageParams = { page: 1, page_size: 10 };
6
6
 
7
7
  export function useFilterParams<R extends Api.Request, AP extends Api.GetParam<R>, BP extends AP>(
8
8
  _api: R,
9
9
  buildParams: () => BP,
10
10
  pageParams = defaultPageParams,
11
11
  ) {
12
- type FinalParams = AP & BP & PageParams
13
- const params = reactive({ ...pageParams, ...buildParams() } as FinalParams)
12
+ type FinalParams = AP & BP & PageParams;
13
+ const params = reactive({ ...pageParams, ...buildParams() } as FinalParams);
14
14
  const update = (newParams?: Partial<FinalParams>) => {
15
- Object.assign(params, { ...buildParams(), ...newParams })
16
- }
15
+ Object.assign(params, { ...buildParams(), ...newParams, __t: Date.now() });
16
+ };
17
17
 
18
- return extendRef(params, { update })
18
+ return extendRef(params, { update });
19
19
  }
@@ -1,31 +1,31 @@
1
- import { useFilterParams } from './useFilterParams'
2
- import { useInfiniteQuery, useQuery } from '@tanstack/vue-query'
1
+ import { useInfiniteQuery, useQuery } from '@tanstack/vue-query';
2
+ import { useFilterParams } from './useFilterParams';
3
3
 
4
4
  /**
5
-
5
+
6
6
  */
7
7
  export function useFilterPaginationQuery<Api extends Api.Request, P extends Api.GetParam<Api>>(apiFn: Api, paramsFn: () => P) {
8
- type Data = Api.GetData<Api>
8
+ type Data = Api.GetData<Api>;
9
9
 
10
- const filterParams = useFilterParams(apiFn, paramsFn)
10
+ const filterParams = useFilterParams(apiFn, paramsFn);
11
11
  const filterQuery = useQuery({
12
12
  keepPreviousData: true,
13
13
  queryKey: [apiFn.id, 'pagination', filterParams],
14
14
  queryFn: () => (apiFn(filterParams) as Promise<Data>),
15
- })
15
+ });
16
16
 
17
- return [filterQuery, filterParams] as const
17
+ return [filterQuery, filterParams] as const;
18
18
  }
19
19
 
20
20
  export function useFilterInfiniteQuery<Api extends Api.Request, P extends Api.GetParam<Api>>(apiFn: Api, paramsFn: () => P) {
21
- type Data = Api.GetData<Api>
21
+ type Data = Api.GetData<Api>;
22
22
 
23
- const filterParams = useFilterParams(apiFn, paramsFn)
23
+ const filterParams = useFilterParams(apiFn, paramsFn);
24
24
  const filterQuery = useInfiniteQuery({
25
25
  keepPreviousData: true,
26
26
  queryKey: [apiFn.id, 'infinite', filterParams],
27
27
  queryFn: ctx => (apiFn({ ...filterParams, ...ctx.pageParam }) as Promise<Data>),
28
- })
28
+ });
29
29
 
30
- return [filterQuery, filterParams] as const
30
+ return [filterQuery, filterParams] as const;
31
31
  }
@@ -1 +1 @@
1
- export { default as ScrollNav } from './src/ScrollNav.vue'
1
+ export { default as ScrollNav } from './src/ScrollNav.vue';
@@ -1,59 +1,59 @@
1
- <script setup lang="ts">
2
- import { computed } from "vue";
3
- import { useElementSize } from '@vueuse/core'
4
-
5
- const props = defineProps<{
6
- selector: string
7
- }>()
8
-
9
- const $content = document.querySelector(props.selector) as HTMLElement
10
- const $contentParent = $content.parentElement
11
- const { height: contentParentH } = useElementSize($contentParent)
12
- const { height: contentH } = useElementSize($content)
13
- const visible = computed(() => contentParentH.value * 2 < contentH.value)
14
-
15
- function scrollTo(top: number) {
16
- $contentParent?.scrollTo({ top })
17
- }
18
- </script>
19
-
20
- <template>
21
- <div v-if="visible" class="wrapper">
22
- <div class="btn" @click="scrollTo(0)">
23
- <i class="i-fluent:arrow-previous-24-filled rotate-90" />
24
- </div>
25
- <div class="btn" @click="scrollTo($contentParent?.scrollHeight ?? Infinity)">
26
- <i class="i-fluent:arrow-previous-24-filled rotate-270" />
27
- </div>
28
- <!-- <div v-if="showReturn" class="btn" @click="toLastY()">
29
- <i class="i-fluent:arrow-hook-down-left-24-filled rotate-270" />
30
- </div> -->
31
- </div>
32
- </template>
33
-
34
- <style lang="scss" scoped>
35
- .wrapper {
36
- font-size: 18px;
37
- }
38
-
39
- .btn {
40
- display: flex;
41
- width: 2em;
42
- height: 2em;
43
- align-items: center;
44
- justify-content: center;
45
- border-radius: 2px;
46
- background: #bcbcbc;
47
- color: #000;
48
- cursor: pointer;
49
- opacity: 0.7;
50
-
51
- &:active {
52
- transform: scale(0.9);
53
- }
54
-
55
- & + & {
56
- margin-top: 1px;
57
- }
58
- }
59
- </style>
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue';
3
+ import { useElementSize } from '@vueuse/core';
4
+
5
+ const props = defineProps<{
6
+ selector: string
7
+ }>();
8
+
9
+ const $content = document.querySelector(props.selector) as HTMLElement;
10
+ const $contentParent = $content.parentElement;
11
+ const { height: contentParentH } = useElementSize($contentParent);
12
+ const { height: contentH } = useElementSize($content);
13
+ const visible = computed(() => contentParentH.value * 2 < contentH.value);
14
+
15
+ function scrollTo(top: number) {
16
+ $contentParent?.scrollTo({ top });
17
+ }
18
+ </script>
19
+
20
+ <template>
21
+ <div v-if="visible" class="wrapper">
22
+ <div class="btn" @click="scrollTo(0)">
23
+ <i class="i-fluent:arrow-previous-24-filled rotate-90" />
24
+ </div>
25
+ <div class="btn" @click="scrollTo($contentParent?.scrollHeight ?? Infinity)">
26
+ <i class="i-fluent:arrow-previous-24-filled rotate-270" />
27
+ </div>
28
+ <!-- <div v-if="showReturn" class="btn" @click="toLastY()">
29
+ <i class="i-fluent:arrow-hook-down-left-24-filled rotate-270" />
30
+ </div> -->
31
+ </div>
32
+ </template>
33
+
34
+ <style lang="scss" scoped>
35
+ .wrapper {
36
+ font-size: 18px;
37
+ }
38
+
39
+ .btn {
40
+ display: flex;
41
+ width: 2em;
42
+ height: 2em;
43
+ align-items: center;
44
+ justify-content: center;
45
+ border-radius: 2px;
46
+ background: #bcbcbc;
47
+ color: #000;
48
+ cursor: pointer;
49
+ opacity: 0.7;
50
+
51
+ &:active {
52
+ transform: scale(0.9);
53
+ }
54
+
55
+ & + & {
56
+ margin-top: 1px;
57
+ }
58
+ }
59
+ </style>
@@ -1,13 +1,13 @@
1
- import Hash from './src/Hash.vue'
2
- import Amount from './src/Amount.vue'
3
- import Datetime from './src/Datetime.vue'
4
- import Duration from './src/Duration.vue'
5
-
6
- export { createTagGetter } from './src/createTagGetter'
7
-
8
- export const Text = {
9
- Hash,
10
- Amount,
11
- Datetime,
12
- Duration,
13
- }
1
+ import Hash from './src/Hash.vue';
2
+ import Amount from './src/Amount.vue';
3
+ import Datetime from './src/Datetime.vue';
4
+ import Duration from './src/Duration.vue';
5
+
6
+ export { createTagGetter } from './src/createTagGetter';
7
+
8
+ export const Text = {
9
+ Hash,
10
+ Amount,
11
+ Datetime,
12
+ Duration,
13
+ };