chore: update prettier and simplify config (#7589)

#### What type of PR is this?

/area ui
/kind cleanup

#### What this PR does / why we need it:

Upgrade Prettier and related plugins, and simplify Prettier configuration.

Now, formatting for all packages will be managed by Prettier in the project root directory.

#### Does this PR introduce a user-facing change?

```release-note
None
```
pull/7594/head^2
Ryan Wang 2025-06-25 17:47:21 +08:00 committed by GitHub
parent 1826c7dcbb
commit 5e28c6db0c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
138 changed files with 587 additions and 720 deletions

View File

@ -1,2 +1,3 @@
pnpm-lock.yaml
packages/api-client
packages/api-client/src
docs

View File

@ -16,7 +16,7 @@
<a href="https://gitpod.io/#https://github.com/halo-dev/console"><img alt="Gitpod ready-to-code" src="https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod&style=flat-square"/></a>
</p>
------------------------------
---
当前仓库已经将 `halo-admin` 改为了 `console`。但对于 Halo 1.x 版本,依旧保持 halo-admin 的概念。
@ -27,7 +27,7 @@ npm install -g pnpm@9
```
```bash
pnpm install
pnpm install
```
```bash

View File

@ -286,13 +286,13 @@ const { operationItems } = useOperationItemExtensionPoint<ListedComment>(
:owner="comment?.owner"
@click="detailModalVisible = true"
/>
<span class="text-sm text-gray-900 whitespace-nowrap">
<span class="whitespace-nowrap text-sm text-gray-900">
{{ $t("core.comment.text.commented_on") }}
</span>
<RouterLink
v-tooltip="`${subjectRefResult.label}`"
:to="subjectRefResult.route || $route"
class="inline-block truncate max-w-md text-sm font-medium text-gray-900 hover:text-gray-600"
class="inline-block max-w-md truncate text-sm font-medium text-gray-900 hover:text-gray-600"
>
{{ subjectRefResult.title }}
</RouterLink>
@ -311,7 +311,7 @@ const { operationItems } = useOperationItemExtensionPoint<ListedComment>(
>
<div class="flex items-center gap-3 text-xs">
<span
class="select-none cursor-pointer text-gray-700 hover:text-gray-900"
class="cursor-pointer select-none text-gray-700 hover:text-gray-900"
@click="handleToggleShowReplies"
>
{{
@ -328,7 +328,7 @@ const { operationItems } = useOperationItemExtensionPoint<ListedComment>(
/>
<HasPermission :permissions="['system:comments:manage']">
<span
class="select-none cursor-pointer text-gray-700 hover:text-gray-900"
class="cursor-pointer select-none text-gray-700 hover:text-gray-900"
@click="replyModal = true"
>
{{ $t("core.comment.operations.reply.button") }}

View File

@ -8,7 +8,7 @@ defineProps<{
</script>
<template>
<div
class="-m-1 p-1 inline-flex items-center gap-1.5 hover:bg-gray-100 rounded-lg cursor-pointer transition-colors"
class="-m-1 inline-flex cursor-pointer items-center gap-1.5 rounded-lg p-1 transition-colors hover:bg-gray-100"
>
<VAvatar circle :src="owner?.avatar" :alt="owner?.displayName" size="xs" />
<span class="text-sm font-medium text-gray-900">

View File

@ -174,7 +174,7 @@ const websiteOfAnonymous = computed(() => {
>
<OwnerButton :owner="comment.owner" />
<pre
class="whitespace-pre-wrap mt-2 break-words text-sm text-gray-900"
class="mt-2 whitespace-pre-wrap break-words text-sm text-gray-900"
>{{ comment.comment.spec.content }}</pre
>
</VDescriptionItem>

View File

@ -71,7 +71,7 @@ watch(
value=""
:validation="['length:0,1024', required ? 'required' : ''].join('|')"
></FormKit>
<div class="flex justify-end w-full sm:max-w-lg">
<div class="flex w-full justify-end sm:max-w-lg">
<VDropdown :classes="['!p-0']" @show="handleCreateEmojiPicker">
<IconMotionLine
class="h-5 w-5 cursor-pointer text-gray-500 transition-all hover:text-gray-900"

View File

@ -223,7 +223,7 @@ const { operationItems } = useOperationItemExtensionPoint<ListedReply>(
:owner="reply?.owner"
@click="detailModalVisible = true"
/>
<span class="text-sm text-gray-900 whitespace-nowrap">
<span class="whitespace-nowrap text-sm text-gray-900">
{{ $t("core.comment.text.replied_below") }}
</span>
</div>
@ -242,7 +242,7 @@ const { operationItems } = useOperationItemExtensionPoint<ListedReply>(
<HasPermission :permissions="['system:comments:manage']">
<div class="flex items-center gap-3 text-xs">
<span
class="select-none cursor-pointer text-gray-700 hover:text-gray-900"
class="cursor-pointer select-none text-gray-700 hover:text-gray-900"
@click="replyModal = true"
>
{{ $t("core.comment.operations.reply.button") }}

View File

@ -310,10 +310,10 @@ watch(
<VEntityField v-if="singlePage.page.spec.cover">
<template #description>
<div
class="aspect-h-2 rounded-md overflow-hidden aspect-w-3 w-20"
class="aspect-h-2 aspect-w-3 w-20 overflow-hidden rounded-md"
>
<img
class="object-cover w-full h-full"
class="h-full w-full object-cover"
:src="
generateThumbnailUrl(singlePage.page.spec.cover, 's')
"

View File

@ -14,9 +14,9 @@ withDefaults(
<template>
<VEntityField v-if="singlePage.page.spec.cover">
<template #description>
<div class="aspect-h-2 rounded-md overflow-hidden aspect-w-3 w-20">
<div class="aspect-h-2 aspect-w-3 w-20 overflow-hidden rounded-md">
<img
class="object-cover w-full h-full"
class="h-full w-full object-cover"
:src="generateThumbnailUrl(singlePage.page.spec.cover, 's')"
/>
</div>

View File

@ -321,10 +321,10 @@ watch(
<VEntityField v-if="post.post.spec.cover">
<template #description>
<div
class="aspect-h-2 rounded-md overflow-hidden aspect-w-3 w-20"
class="aspect-h-2 aspect-w-3 w-20 overflow-hidden rounded-md"
>
<img
class="object-cover w-full h-full"
class="h-full w-full object-cover"
:src="generateThumbnailUrl(post.post.spec.cover, 's')"
/>
</div>

View File

@ -86,7 +86,7 @@ const handleOpenCreateByParentModal = () => {
</script>
<template>
<div
class="px-4 py-3 hover:bg-gray-50 w-full group items-center flex justify-between relative"
class="group relative flex w-full items-center justify-between px-4 py-3 hover:bg-gray-50"
>
<div>
<div
@ -98,7 +98,7 @@ const handleOpenCreateByParentModal = () => {
>
<IconList class="h-3.5 w-3.5" />
</div>
<div class="gap-1 flex flex-col">
<div class="flex flex-col gap-1">
<div class="inline-flex items-center gap-2">
<span class="truncate text-sm font-medium text-gray-900">
{{ categoryTreeNode.spec.displayName }}

View File

@ -14,9 +14,9 @@ withDefaults(
<template>
<VEntityField v-if="post.post.spec.cover">
<template #description>
<div class="aspect-h-2 rounded-md overflow-hidden aspect-w-3 w-20">
<div class="aspect-h-2 aspect-w-3 w-20 overflow-hidden rounded-md">
<img
class="object-cover w-full h-full"
class="h-full w-full object-cover"
:src="generateThumbnailUrl(post.post.spec.cover, 's')"
/>
</div>

View File

@ -329,7 +329,7 @@ function handleCopyFromLayout(breakpoint: string) {
</h2>
<div
class="hidden sm:block"
:class="{ 'opacity-50 !cursor-progress': isLoading }"
:class="{ '!cursor-progress opacity-50': isLoading }"
>
<VTabbar
:active-id="selectBreakpoint"

View File

@ -1,7 +1,7 @@
<script setup lang="ts"></script>
<template>
<div
class="h-full text-base w-8 flex cursor-pointer items-center justify-center hover:opacity-80 text-white transition-all"
class="flex h-full w-8 cursor-pointer items-center justify-center text-base text-white transition-all hover:opacity-80"
>
<slot />
</div>

View File

@ -6,22 +6,22 @@ defineProps<{
</script>
<template>
<div
class="flex flex-col rounded-lg overflow-hidden ring-1 ring-[#eaecf0] shadow-sm bg-white w-full h-full"
class="flex h-full w-full flex-col overflow-hidden rounded-lg bg-white shadow-sm ring-1 ring-[#eaecf0]"
>
<div
v-if="title || $slots.title || $slots.actions"
class="flex flex-none justify-between h-10 items-center px-4 border-b border-[#eaecf0]"
class="flex h-10 flex-none items-center justify-between border-b border-[#eaecf0] px-4"
>
<slot name="title">
<div class="text-base font-medium flex-1 shrink">
<div class="flex-1 shrink text-base font-medium">
{{ title }}
</div>
</slot>
<div class="text-base font-medium flex-none">
<div class="flex-none text-base font-medium">
<slot name="actions" />
</div>
</div>
<div :class="bodyClass" class="flex-1 min-h-0 shrink w-full">
<div :class="bodyClass" class="min-h-0 w-full flex-1 shrink">
<slot />
</div>
</div>

View File

@ -62,7 +62,7 @@ function handleSaveConfig(config: Record<string, unknown>) {
@update:config="handleSaveConfig"
/>
<div
class="absolute z-[100] hidden h-8 right-0 top-0 rounded-tr-lg bg-gray-100 overflow-hidden group-hover/grid-item:inline-flex items-center"
class="absolute right-0 top-0 z-[100] hidden h-8 items-center overflow-hidden rounded-tr-lg bg-gray-100 group-hover/grid-item:inline-flex"
>
<ActionButton
v-if="widgetDefinition?.configFormKitSchema"

View File

@ -24,14 +24,17 @@ const groupedWidgetDefinitions = computed(() => {
(widget) => activeId.value === "" || widget.group === activeId.value
);
const groups = filteredWidgets?.reduce((acc, widget) => {
const key = `${widget.defaultSize.w}-${widget.defaultSize.h}`;
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(widget);
return acc;
}, {} as Record<string, DashboardWidgetDefinition[]>);
const groups = filteredWidgets?.reduce(
(acc, widget) => {
const key = `${widget.defaultSize.w}-${widget.defaultSize.h}`;
if (!acc[key]) {
acc[key] = [];
}
acc[key].push(widget);
return acc;
},
{} as Record<string, DashboardWidgetDefinition[]>
);
return Object.entries(groups || {})
.map(([key, widgets]) => {
@ -48,11 +51,14 @@ const groupedWidgetDefinitions = computed(() => {
});
const groupWidgetDefinitions = computed(() => {
return availableWidgetDefinitions?.value?.reduce((acc, item) => {
acc[item.group] = acc[item.group] || [];
acc[item.group].push(item);
return acc;
}, {} as Record<string, DashboardWidgetDefinition[]>);
return availableWidgetDefinitions?.value?.reduce(
(acc, item) => {
acc[item.group] = acc[item.group] || [];
acc[item.group].push(item);
return acc;
},
{} as Record<string, DashboardWidgetDefinition[]>
);
});
const groupWidgetDefinitionsKeys = computed(() => {
@ -80,7 +86,7 @@ const groupWidgetDefinitionsKeys = computed(() => {
]"
type="outline"
></VTabbar>
<div class="mt-4 flex flex-col gap-5 -m-2">
<div class="-m-2 mt-4 flex flex-col gap-5">
<div
v-for="(group, index) in groupedWidgetDefinitions"
:key="index"
@ -99,7 +105,7 @@ const groupWidgetDefinitionsKeys = computed(() => {
class="cursor-pointer p-2"
@click="emit('add-widget', item)"
>
<div class="pointer-events-none w-full h-full">
<div class="pointer-events-none h-full w-full">
<component
:is="item.component"
preview-mode

View File

@ -81,13 +81,13 @@ const handleDelete = async () => {
:owner="comment?.owner"
@click="detailModalVisible = true"
/>
<span class="text-sm text-gray-900 whitespace-nowrap">
<span class="whitespace-nowrap text-sm text-gray-900">
{{ $t("core.comment.text.commented_on") }}
</span>
<RouterLink
v-tooltip="`${subjectRefResult.label}`"
:to="subjectRefResult.route || $route"
class="inline-block truncate max-w-md text-sm font-medium text-gray-900 hover:text-gray-600"
class="inline-block max-w-md truncate text-sm font-medium text-gray-900 hover:text-gray-600"
>
{{ subjectRefResult.title }}
</RouterLink>
@ -101,19 +101,19 @@ const handleDelete = async () => {
</a>
</div>
<pre
class="whitespace-pre-wrap break-words text-sm text-gray-900 line-clamp-4"
class="line-clamp-4 whitespace-pre-wrap break-words text-sm text-gray-900"
>{{ comment?.comment?.spec.content }}</pre
>
<HasPermission :permissions="['system:comments:manage']">
<div class="flex items-center gap-3 text-xs">
<span
class="select-none cursor-pointer text-gray-700 hover:text-gray-900"
class="cursor-pointer select-none text-gray-700 hover:text-gray-900"
@click="detailModalVisible = true"
>
{{ $t("core.comment.operations.review.button") }}
</span>
<span
class="select-none cursor-pointer text-gray-700 hover:text-red-600"
class="cursor-pointer select-none text-gray-700 hover:text-red-600"
@click="handleDelete"
>
{{ $t("core.common.buttons.delete") }}

View File

@ -20,7 +20,7 @@ defineProps<{
>
<div
v-if="!config.url"
class="flex items-center justify-center w-full h-full"
class="flex h-full w-full items-center justify-center"
>
<span class="text-sm text-gray-600">
{{ $t("core.dashboard.widgets.presets.iframe.empty.title") }}
@ -32,7 +32,7 @@ defineProps<{
sandbox="allow-scripts allow-same-origin"
credentialless
referrerpolicy="no-referrer"
class="w-full h-full border-none"
class="h-full w-full border-none"
:class="{
'pointer-events-none': editMode,
}"

View File

@ -217,12 +217,12 @@ const availableItems = computed(() => {
<WidgetCard v-bind="$attrs" :body-class="['@container', '!overflow-auto']">
<template #title>
<div class="inline-flex items-center gap-2">
<div class="text-base font-medium flex-1 shrink">
<div class="flex-1 shrink text-base font-medium">
{{ $t("core.dashboard.widgets.presets.quickaction.title") }}
</div>
<IconSettings
v-if="editMode"
class="hover:text-gray-600 cursor-pointer"
class="cursor-pointer hover:text-gray-600"
@click="configVisible = true"
/>
</div>

View File

@ -81,7 +81,7 @@ async function handleSave(config: StackWidgetConfig) {
v-if="!config.widgets?.length"
:title="$t('core.dashboard.widgets.presets.stack.title')"
>
<div class="flex items-center justify-center w-full h-full">
<div class="flex h-full w-full items-center justify-center">
<VButton @click="configVisible = true">
{{
$t(
@ -93,21 +93,21 @@ async function handleSave(config: StackWidgetConfig) {
</WidgetCard>
<div
v-else
class="bg-white w-full h-full rounded-lg relative group/stack-item overflow-hidden"
class="group/stack-item relative h-full w-full overflow-hidden rounded-lg bg-white"
@mouseenter="stopAutoPlay"
@mouseleave="startAutoPlay"
>
<div
v-if="editMode || previewMode"
class="flex absolute z-10 bg-white inset-0 rounded-t-lg flex-none justify-between h-10 items-center px-4 border-b border-[#eaecf0]"
class="absolute inset-0 z-10 flex h-10 flex-none items-center justify-between rounded-t-lg border-b border-[#eaecf0] bg-white px-4"
>
<div class="inline-flex items-center gap-2">
<div class="text-base font-medium flex-1 shrink">
<div class="flex-1 shrink text-base font-medium">
{{ $t("core.dashboard.widgets.presets.stack.title") }}
</div>
<IconSettings
v-if="editMode"
class="hover:text-gray-600 cursor-pointer"
class="cursor-pointer hover:text-gray-600"
@click="configVisible = true"
/>
</div>
@ -123,7 +123,7 @@ async function handleSave(config: StackWidgetConfig) {
</TransitionGroup>
<div
class="absolute bottom-2 left-0 right-0 z-10 flex justify-center group-hover/stack-item:opacity-100 opacity-0 transition-all duration-200"
class="absolute bottom-2 left-0 right-0 z-10 flex justify-center opacity-0 transition-all duration-200 group-hover/stack-item:opacity-100"
>
<IndexIndicator
:index="index"

View File

@ -137,7 +137,7 @@ function handleMoveWidget(widget: SimpleWidget, direction: -1 | 1) {
)
"
/>
<div class="py-4 flex flex-col gap-4">
<div class="flex flex-col gap-4 py-4">
<label
class="formkit-label block text-sm font-medium text-gray-700 formkit-invalid:text-red-500"
>
@ -147,7 +147,7 @@ function handleMoveWidget(widget: SimpleWidget, direction: -1 | 1) {
)
}}
</label>
<div class="flex flex-col gap-2 border border-dashed p-2 rounded-lg">
<div class="flex flex-col gap-2 rounded-lg border border-dashed p-2">
<WidgetEditableItem
v-for="(widget, index) in widgets"
:key="widget.id"
@ -173,7 +173,7 @@ function handleMoveWidget(widget: SimpleWidget, direction: -1 | 1) {
</template>
</WidgetEditableItem>
<div class="flex justify-left">
<div class="justify-left flex">
<VButton @click="widgetsHubModalVisible = true">
{{ $t("core.common.buttons.add") }}
</VButton>

View File

@ -15,11 +15,11 @@ const emit = defineEmits<{
<template>
<div
class="bg-white rounded-full p-1 flex gap-4 items-center hover:shadow transition-all"
class="flex items-center gap-4 rounded-full bg-white p-1 transition-all hover:shadow"
>
<button
v-if="total > 1"
class="w-7 h-7 flex items-center justify-center rounded-full bg-transparent hover:bg-gray-100 transition-all duration-200 focus:outline-none group"
class="group flex h-7 w-7 items-center justify-center rounded-full bg-transparent transition-all duration-200 hover:bg-gray-100 focus:outline-none"
@click="emit('prev')"
>
<IconArrowLeft class="text-gray-400 group-hover:text-gray-900" />
@ -33,9 +33,9 @@ const emit = defineEmits<{
@click="emit('update:index', i - 1)"
>
<div
class="w-2 h-2 rounded-full transition-all duration-200 ease-in-out transform"
class="h-2 w-2 transform rounded-full transition-all duration-200 ease-in-out"
:class="{
'bg-primary scale-150': index === i - 1,
'scale-150 bg-primary': index === i - 1,
'bg-gray-300 group-hover:bg-gray-400': index !== i - 1,
}"
/>
@ -44,7 +44,7 @@ const emit = defineEmits<{
<button
v-if="total > 1"
class="w-7 h-7 flex items-center justify-center rounded-full bg-transparent hover:bg-gray-100 transition-all duration-200 focus:outline-none group"
class="group flex h-7 w-7 items-center justify-center rounded-full bg-transparent transition-all duration-200 hover:bg-gray-100 focus:outline-none"
@click="emit('next')"
>
<IconArrowRight class="text-gray-400 group-hover:text-gray-900" />

View File

@ -55,7 +55,7 @@ function handleSaveConfig(config: Record<string, unknown>) {
@update:config="handleSaveConfig"
/>
<div
class="absolute hidden h-8 right-0 top-0 rounded-tr-lg bg-gray-100 overflow-hidden group-hover/grid-item:inline-flex items-center"
class="absolute right-0 top-0 hidden h-8 items-center overflow-hidden rounded-tr-lg bg-gray-100 group-hover/grid-item:inline-flex"
>
<slot name="actions" />
<ActionButton

View File

@ -24,7 +24,7 @@ const widgetDefinition = computed(() => {
<template>
<div
v-if="currentUserHasPermission(widgetDefinition?.permissions)"
class="relative w-full h-full"
class="relative h-full w-full"
>
<component :is="widgetDefinition?.component" :config="item.config" />
</div>

View File

@ -319,7 +319,7 @@ function getMenuItemRefDisplayName(menuItem: MenuTreeItem) {
>
<template #default="{ node }">
<div
class="px-4 py-3 hover:bg-gray-50 w-full group items-center flex justify-between relative"
class="group relative flex w-full items-center justify-between px-4 py-3 hover:bg-gray-50"
>
<div>
<div
@ -331,7 +331,7 @@ function getMenuItemRefDisplayName(menuItem: MenuTreeItem) {
>
<IconList class="h-3.5 w-3.5" />
</div>
<div class="gap-1 flex flex-col">
<div class="flex flex-col gap-1">
<div class="inline-flex items-center gap-2">
<span
class="truncate text-sm font-medium text-gray-900"

View File

@ -140,12 +140,12 @@ const currentRoleTemplates = computed(() => {
<div v-if="selectedRoleNames.length">
<div
v-if="selectedRoleNames.includes(SUPER_ROLE_NAME)"
class="text-sm text-gray-600 mt-4"
class="mt-4 text-sm text-gray-600"
>
{{ $t("core.user.grant_permission_modal.roles_preview.all") }}
</div>
<div v-else-if="currentRoleTemplates?.length" class="space-y-3 mt-4">
<div v-else-if="currentRoleTemplates?.length" class="mt-4 space-y-3">
<span class="text-sm text-gray-600">
{{ $t("core.user.grant_permission_modal.roles_preview.includes") }}
</span>

View File

@ -20,7 +20,7 @@ const { roleTemplateGroups } = useRoleTemplateSelection(roleTemplates);
</script>
<template>
<dl
class="divide-y divide-gray-100 border border-gray-100 rounded-base overflow-hidden"
class="divide-y divide-gray-100 overflow-hidden rounded-base border border-gray-100"
>
<div
v-for="(group, index) in roleTemplateGroups"

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />

View File

@ -19,15 +19,12 @@
"test:unit:coverage": "vitest run --coverage",
"typecheck": "vue-tsc --noEmit -p tsconfig.app.json --composite false && pnpm run typecheck:packages",
"lint": "eslint . --max-warnings=0 -f html -o build/lint-result/index.html",
"prettier": "prettier --write \"./{src,uc-src,console-src}/**/*.{vue,js,jsx,ts,tsx,css,scss,json,yml,yaml,html}\" && pnpm run prettier:packages",
"prettier": "prettier . --write",
"typecheck:packages": "pnpm --parallel --filter \"./packages/**\" run typecheck",
"prettier:packages": "pnpm --parallel --filter \"./packages/**\" prettier",
"test:unit:packages": "pnpm --parallel --filter \"./packages/**\" run test:unit"
},
"lint-staged": {
"*.{vue,js,jsx,ts,tsx,css,scss,json,yml,yaml,html}": [
"prettier --write"
],
"**/*": "prettier --write --ignore-unknown",
"*.{ts,mts,tsx,vue}": [
"eslint --fix --max-warnings=0"
]
@ -35,6 +32,13 @@
"browserslist": [
"defaults"
],
"prettier": {
"plugins": [
"prettier-plugin-organize-imports",
"prettier-plugin-tailwindcss"
],
"trailingComma": "es5"
},
"resolutions": {
"axios": "^1.7.9"
},
@ -124,9 +128,9 @@
"@types/randomstring": "^1.1.8",
"@types/ua-parser-js": "^0.7.39",
"@typescript/native-preview": "7.0.0-dev.20250619.1",
"@vitest/eslint-plugin": "^1.2.7",
"@vitejs/plugin-vue": "^6.0.0",
"@vitejs/plugin-vue-jsx": "^5.0.0",
"@vitest/eslint-plugin": "^1.2.7",
"@vitest/ui": "^3.1.4",
"@vue/compiler-sfc": "^3.5.16",
"@vue/eslint-config-prettier": "^10.2.0",
@ -144,9 +148,9 @@
"npm-run-all": "^4.1.5",
"postcss": "^8.4.21",
"postcss-viewport-height-correction": "^1.1.1",
"prettier": "^2.8.8",
"prettier": "^3.6.0",
"prettier-plugin-organize-imports": "^4.1.0",
"prettier-plugin-tailwindcss": "^0.1.13",
"prettier-plugin-tailwindcss": "^0.6.13",
"rollup-plugin-gzip": "^3.1.0",
"sass-embedded": "^1.82.0",
"start-server-and-test": "^1.14.0",

View File

@ -1,3 +0,0 @@
module.exports = {
plugins: ["../../prettier.config.cjs"],
};

View File

@ -14,8 +14,8 @@ import {
createConsoleApiClient,
createUcApiClient,
createPublicApiClient,
axiosInstance
} from "@halo-dev/api-client"
axiosInstance,
} from "@halo-dev/api-client";
```
- **coreApiClient**: 为 Halo 所有自定义模型的 CRUD 接口封装的 api client。
@ -37,11 +37,11 @@ pnpm install @halo-dev/api-client axios
由于已经在 Console 和 UC 项目中引入并设置好了 Axios 拦截器,所以直接使用即可:
```javascript
import { coreApiClient } from "@halo-dev/api-client"
import { coreApiClient } from "@halo-dev/api-client";
coreApiClient.content.post.listPost().then(response => {
coreApiClient.content.post.listPost().then((response) => {
// handle response
})
});
```
此外,在最新的 `@halo-dev/ui-plugin-bundler-kit@2.17.0` 中,已经排除了 `@halo-dev/api-client`、`axios` 依赖,所以最终产物中的相关依赖会自动使用 Halo 本身提供的依赖,无需关心最终产物大小。
@ -55,15 +55,15 @@ pnpm install @halo-dev/api-client axios
```
```javascript
import axios from "axios"
import axios from "axios";
const axiosInstance = axios.create({
baseURL: "http://localhost:8090"
})
baseURL: "http://localhost:8090",
});
const coreApiClient = createCoreApiClient(axiosInstance)
const coreApiClient = createCoreApiClient(axiosInstance);
coreApiClient.content.post.listPost().then(response => {
coreApiClient.content.post.listPost().then((response) => {
// handle response
})
});
```

View File

@ -34,6 +34,7 @@ import {
PersonalAccessTokenV1alpha1UcApi,
PluginV1alpha1Api,
PluginV1alpha1ConsoleApi,
PolicyAlpha1ConsoleApi,
PolicyTemplateV1alpha1Api,
PolicyV1alpha1Api,
PostV1alpha1Api,
@ -63,10 +64,9 @@ import {
ThemeV1alpha1ConsoleApi,
TwoFactorAuthV1alpha1UcApi,
UserConnectionV1alpha1Api,
UserPreferenceV1alpha1UcApi,
UserV1alpha1Api,
UserV1alpha1ConsoleApi,
UserPreferenceV1alpha1UcApi,
PolicyAlpha1ConsoleApi,
} from "../src";
const defaultAxiosInstance = axios.create({

View File

@ -1,3 +1,2 @@
export * from "../src";
export * from "./api-client";

View File

@ -16,6 +16,6 @@ export default defineConfig({
minify: true,
exports: true,
dts: {
tsgo: true
}
tsgo: true,
},
});

View File

@ -1,7 +1,7 @@
import type { Preview } from "@storybook/vue3";
import "../src/styles/tailwind.css";
import "overlayscrollbars/overlayscrollbars.css";
import "../src/styles/tailwind.css";
const preview: Preview = {
parameters: {

View File

@ -1,5 +1,3 @@
/// <reference types="vite/client" />
/// <reference types="histoire" />
/// <reference types="unplugin-icons/types/vue" />

View File

@ -18,7 +18,6 @@
"test:unit:ui": "vitest --watch --ui",
"test:unit:coverage": "vitest run --coverage",
"typecheck": "vue-tsc --noEmit -p tsconfig.app.json --composite false",
"prettier": "prettier --write './src/**/*.{vue,js,jsx,ts,tsx,css,scss,json,yml,yaml,html}'",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build"
},

View File

@ -1,3 +0,0 @@
module.exports = {
plugins: ["../../prettier.config.cjs"],
};

View File

@ -76,58 +76,39 @@ const handleClose = () => {
<style lang="scss" scoped>
.alert-wrapper {
@apply flex
flex-col
box-border
border
rounded-base;
@apply box-border flex flex-col rounded-base border;
padding: 12px 16px;
.alert-header {
@apply flex;
.alert-icon {
@apply self-center
mr-3
text-lg;
@apply mr-3 self-center text-lg;
}
.alert-title {
@apply self-center
mr-3
flex-1
font-medium
text-sm;
@apply mr-3 flex-1 self-center text-sm font-medium;
}
.alert-close {
@apply self-center
cursor-pointer
rounded-full
p-0.5;
@apply cursor-pointer self-center rounded-full p-0.5;
&:hover {
@apply transition-all
bg-gray-300
text-white;
@apply bg-gray-300 text-white transition-all;
}
}
}
.alert-description {
@apply text-xs
mt-2;
@apply mt-2 text-xs;
}
.alert-actions {
@apply border-t
mt-3
pt-2;
@apply mt-3 border-t pt-2;
}
&.alert-default {
@apply bg-gray-50
border-gray-300;
@apply border-gray-300 bg-gray-50;
.alert-icon,
.alert-description {
@ -141,8 +122,7 @@ const handleClose = () => {
}
&.alert-success {
@apply bg-green-50
border-green-300;
@apply border-green-300 bg-green-50;
.alert-icon,
.alert-description {
@ -156,8 +136,7 @@ const handleClose = () => {
}
&.alert-info {
@apply bg-sky-50
border-sky-300;
@apply border-sky-300 bg-sky-50;
.alert-icon,
.alert-description {
@ -171,8 +150,7 @@ const handleClose = () => {
}
&.alert-warning {
@apply bg-orange-50
border-orange-300;
@apply border-orange-300 bg-orange-50;
.alert-icon,
.alert-description {
@ -186,8 +164,7 @@ const handleClose = () => {
}
&.alert-error {
@apply bg-red-50
border-red-300;
@apply border-red-300 bg-red-50;
.alert-icon,
.alert-description {

View File

@ -129,23 +129,23 @@ const placeholderText = computed(() => {
@apply inline-flex items-center justify-center overflow-hidden bg-gray-100;
img {
@apply w-full h-full object-cover;
@apply h-full w-full object-cover;
}
.avatar-fallback {
@apply w-full h-full flex items-center justify-center;
@apply flex h-full w-full items-center justify-center;
}
.avatar-loading {
@apply animate-spin w-5 h-5;
@apply h-5 w-5 animate-spin;
}
.avatar-placeholder {
@apply text-sm text-gray-800 font-medium;
@apply text-sm font-medium text-gray-800;
}
.avatar-error {
@apply w-5 h-5 text-red-500;
@apply h-5 w-5 text-red-500;
}
&.avatar-circle {
@ -157,7 +157,7 @@ const placeholderText = computed(() => {
}
&.avatar-xs {
@apply w-6 h-6;
@apply h-6 w-6;
.avatar-placeholder {
@apply text-xs;
@ -165,7 +165,7 @@ const placeholderText = computed(() => {
}
&.avatar-sm {
@apply w-8 h-8;
@apply h-8 w-8;
.avatar-placeholder {
@apply text-xs;
@ -173,11 +173,11 @@ const placeholderText = computed(() => {
}
&.avatar-md {
@apply w-10 h-10;
@apply h-10 w-10;
}
&.avatar-lg {
@apply w-12 h-12;
@apply h-12 w-12;
}
}
</style>

View File

@ -21,10 +21,10 @@ provide(AvatarGroupContextInjectionKey, props);
<style lang="scss">
.avatar-group-wrapper {
@apply -space-x-2.5 inline-flex;
@apply inline-flex -space-x-2.5;
> * {
@apply hover:z-10 ring-2 ring-white transition-all;
@apply ring-2 ring-white transition-all hover:z-10;
}
}
</style>

View File

@ -27,26 +27,14 @@ defineProps<{
</template>
<style lang="scss">
.card-wrapper {
@apply box-border
flex
flex-col
bg-white
shadow-sm
rounded-base
ring-1
ring-[#eaecf0];
@apply box-border flex flex-col rounded-base bg-white shadow-sm ring-1 ring-[#eaecf0];
.card-header {
@apply flex
justify-between
rounded-t-base
overflow-hidden;
@apply flex justify-between overflow-hidden rounded-t-base;
border-bottom: 1px solid #eaecf0;
.card-header-title {
@apply self-center
text-base
font-bold;
@apply self-center text-base font-bold;
padding: 12px 16px;
}
@ -56,12 +44,12 @@ defineProps<{
}
.card-body {
@apply rounded-base overflow-hidden;
@apply overflow-hidden rounded-base;
padding: 12px 16px;
}
.card-footer {
@apply rounded-b-base overflow-hidden;
@apply overflow-hidden rounded-b-base;
border-top: 1px solid #eaecf0;
padding: 12px 16px;
}

View File

@ -36,7 +36,7 @@ withDefaults(
}
.description-item__content {
@apply mt-1 text-sm text-gray-900 sm:col-span-6 md:col-span-5 lg:col-span-3 sm:mt-0;
@apply mt-1 text-sm text-gray-900 sm:col-span-6 sm:mt-0 md:col-span-5 lg:col-span-3;
}
}
</style>

View File

@ -90,22 +90,22 @@ const handleClose = () => {
:data-unique-id="uniqueId"
@close="handleCancel()"
>
<div class="flex justify-between items-start py-2 mb-2">
<div class="mb-2 flex items-start justify-between py-2">
<div class="flex flex-row items-center gap-3">
<component
:is="icons[type].icon"
:class="`text-${icons[type].color}-500`"
class="w-6 h-6 flex-none"
class="h-6 w-6 flex-none"
></component>
<div class="text-base text-gray-900 font-bold">{{ title }}</div>
<div class="text-base font-bold text-gray-900">{{ title }}</div>
</div>
<div>
<IconClose class="cursor-pointer" @click="handleCancel" />
</div>
</div>
<div class="flex items-center gap-4">
<div class="flex-1 flex items-stretch">
<div class="text-sm text-gray-700 break-all">{{ description }}</div>
<div class="flex flex-1 items-stretch">
<div class="break-all text-sm text-gray-700">{{ description }}</div>
</div>
</div>
<template #footer>

View File

@ -1,2 +1,2 @@
export { default as VDialog } from "./Dialog.vue";
export { Dialog } from "./dialog-manager";
export { default as VDialog } from "./Dialog.vue";

View File

@ -54,7 +54,7 @@ function onClick(e: MouseEvent) {
<style lang="scss">
.dropdown-item-wrapper {
@apply flex w-full cursor-pointer justify-between items-center gap-1 rounded px-4 py-2 text-sm;
@apply flex w-full cursor-pointer items-center justify-between gap-1 rounded px-4 py-2 text-sm;
&--default {
@apply text-gray-700 hover:bg-gray-100 hover:text-gray-900;
@ -73,7 +73,7 @@ function onClick(e: MouseEvent) {
}
&--disabled {
@apply opacity-70 cursor-not-allowed;
@apply cursor-not-allowed opacity-70;
}
}
</style>

View File

@ -27,31 +27,18 @@ defineProps<{
</template>
<style lang="scss">
.empty-wrapper {
@apply flex
flex-col
items-center
justify-center
my-10
px-10;
@apply my-10 flex flex-col items-center justify-center px-10;
.empty-title {
@apply text-sm
text-gray-900
text-center
font-medium;
@apply text-center text-sm font-medium text-gray-900;
}
.empty-message {
@apply text-gray-500
text-xs
text-center
mt-1.5;
@apply mt-1.5 text-center text-xs text-gray-500;
}
.empty-actions {
@apply flex
flex-row
mt-5;
@apply mt-5 flex flex-row;
}
}
</style>

View File

@ -61,7 +61,7 @@ const classes = computed(() => {
</template>
<style lang="scss">
.entity-wrapper {
@apply relative transition-all hover:bg-gray-50 w-full;
@apply relative w-full transition-all hover:bg-gray-50;
&.entity-selected {
@apply bg-gray-100;
@ -72,7 +72,7 @@ const classes = computed(() => {
}
.entity-body {
@apply relative flex flex-row items-center w-full;
@apply relative flex w-full flex-row items-center;
}
.entity-checkbox {
@ -81,7 +81,7 @@ const classes = computed(() => {
.entity-start-wrapper,
.entity-end-wrapper {
@apply align-middle w-auto px-4 py-3;
@apply w-auto px-4 py-3 align-middle;
}
.entity-start {
@ -89,7 +89,7 @@ const classes = computed(() => {
}
.entity-end {
@apply flex items-center gap-6 justify-end;
@apply flex items-center justify-end gap-6;
}
.entity-dropdown {

View File

@ -78,13 +78,13 @@ function getWidthStyleValue(value: string | number) {
<style lang="scss">
.entity-field-wrapper {
@apply inline-flex flex-col gap-1 max-w-xs;
@apply inline-flex max-w-xs flex-col gap-1;
.entity-field-title-body {
@apply inline-flex items-center flex-row whitespace-nowrap;
@apply inline-flex flex-row items-center whitespace-nowrap;
.entity-field-title {
@apply truncate text-sm font-medium text-gray-900 mr-2;
@apply mr-2 truncate text-sm font-medium text-gray-900;
}
}
@ -92,7 +92,7 @@ function getWidthStyleValue(value: string | number) {
@apply inline-flex items-center whitespace-nowrap;
.entity-field-description {
@apply text-xs text-gray-500 truncate;
@apply truncate text-xs text-gray-500;
}
}
}

View File

@ -84,20 +84,11 @@ function handleExpand() {
}
.menu-item-title {
@apply transition-all
text-base
flex
select-none
relative
px-2
py-[0.4rem]
font-normal
rounded-base;
@apply relative flex select-none rounded-base px-2 py-[0.4rem] text-base font-normal transition-all;
&:hover,
&.active {
@apply bg-gray-100
font-medium;
@apply bg-gray-100 font-medium;
}
&.active::after {
@ -113,7 +104,7 @@ function handleExpand() {
}
.menu-icon-collapse {
@apply group-hover:bg-gray-200 p-0.5 rounded-full;
@apply rounded-full p-0.5 group-hover:bg-gray-200;
&.open {
@apply bg-gray-200;
@ -132,7 +123,7 @@ function handleExpand() {
}
.sub-menu-items {
@apply pl-5 my-1;
@apply my-1 pl-5;
.menu-item-title {
@apply p-1.5 text-sm;

View File

@ -187,38 +187,15 @@ watch(
<style lang="scss">
.modal-wrapper {
@apply fixed
left-0
h-full
w-full
flex
flex-row
items-start
justify-center
top-0
py-10;
@apply fixed left-0 top-0 flex h-full w-full flex-row items-start justify-center py-10;
z-index: 2000;
.modal-layer {
@apply flex-none
absolute
top-0
left-0
h-full
w-full
transition-opacity
bg-gray-500
bg-opacity-75;
@apply absolute left-0 top-0 h-full w-full flex-none bg-gray-500 bg-opacity-75 transition-opacity;
}
.modal-content {
@apply flex
flex-col
relative
bg-white
items-stretch
shadow-xl
rounded-base;
@apply relative flex flex-col items-stretch rounded-base bg-white shadow-xl;
width: calc(100vw - 20px);
max-height: calc(100vh - 5rem);
@ -227,44 +204,23 @@ watch(
}
.modal-header {
@apply flex
justify-between
border-b
items-center
select-none;
@apply flex select-none items-center justify-between border-b;
padding: 10px 16px;
.modal-header-title {
@apply text-base
font-medium
truncate;
@apply truncate text-base font-medium;
}
.modal-header-actions {
@apply flex
flex-row
gap-2;
@apply flex flex-row gap-2;
span {
@apply cursor-pointer
rounded-full
w-7
h-7
inline-flex
items-center
justify-center
hover:bg-gray-100
select-none
text-gray-600
hover:text-gray-900
group-hover:hidden;
@apply inline-flex h-7 w-7 cursor-pointer select-none items-center justify-center rounded-full text-gray-600 hover:bg-gray-100 hover:text-gray-900 group-hover:hidden;
}
}
}
.modal-body {
@apply overflow-y-hidden
overflow-x-hidden
flex-1;
@apply flex-1 overflow-x-hidden overflow-y-hidden;
word-wrap: break-word;
padding: 12px 16px;
}
@ -276,7 +232,7 @@ watch(
}
&.modal-wrapper-centered {
@apply py-0 items-center;
@apply items-center py-0;
.modal-content {
max-height: calc(100vh - 20px) !important;
}

View File

@ -135,22 +135,22 @@ const next = () => {
<style lang="scss">
.pagination {
@apply bg-white flex items-center flex-1 gap-2;
@apply flex flex-1 items-center gap-2 bg-white;
&__total {
@apply hidden sm:block text-sm text-gray-500;
@apply hidden text-sm text-gray-500 sm:block;
}
&__controller {
@apply flex items-center gap-2 flex-1 justify-end;
@apply flex flex-1 items-center justify-end gap-2;
}
&__nav {
@apply relative z-0 inline-flex rounded-base shadow-sm -space-x-px;
@apply relative z-0 inline-flex -space-x-px rounded-base shadow-sm;
}
&__btn {
@apply relative h-8 outline-none inline-flex items-center px-2 py-1.5 rounded-base border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer disabled:cursor-not-allowed;
@apply relative inline-flex h-8 cursor-pointer items-center rounded-base border border-gray-300 bg-white px-2 py-1.5 text-sm font-medium text-gray-500 outline-none hover:bg-gray-50 disabled:cursor-not-allowed;
&--prev {
@apply rounded-r-none;
@ -166,7 +166,7 @@ const next = () => {
}
&__select {
@apply h-8 border outline-none rounded-base pr-10 border-solid px-2 text-gray-800 text-sm border-gray-300 focus:border-primary;
@apply h-8 rounded-base border border-solid border-gray-300 px-2 pr-10 text-sm text-gray-800 outline-none focus:border-primary;
}
&__select-label {

View File

@ -32,8 +32,7 @@ const wrapperClasses = computed(() => {
</template>
<style lang="scss">
.space-wrapper {
@apply inline-flex
box-border;
@apply box-border inline-flex;
&.space-direction-row {
@apply flex-row;

View File

@ -40,7 +40,7 @@ const classes = computed(() => {
}
.status-dot-text {
@apply text-gray-500 text-xs whitespace-nowrap;
@apply whitespace-nowrap text-xs text-gray-500;
}
&.status-dot-animate {

View File

@ -75,41 +75,17 @@ const handleChange = () => {
</template>
<style lang="scss">
.switch-wrapper {
@apply inline-flex
box-border;
@apply box-border inline-flex;
.switch-inner {
@apply relative
inline-flex
flex-shrink-0
h-6
w-11
border-2
border-transparent
rounded-full
cursor-pointer
transition-colors
ease-in-out
duration-200;
@apply relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out;
&.switch-disabled {
@apply opacity-60
cursor-not-allowed;
@apply cursor-not-allowed opacity-60;
}
.switch-indicator {
@apply pointer-events-none
inline-block
h-5
w-5
rounded-full
bg-white
shadow
transform
ring-0
transition
ease-in-out
duration-200;
@apply pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out;
}
}
}

View File

@ -225,43 +225,17 @@ onUnmounted(() => {
.tabbar-wrapper {
@apply relative;
.indicator {
@apply absolute
top-0
z-10
w-20
h-full
flex
items-center
from-transparent
from-10%
via-white/80
via-30%
to-white
to-70%
pt-1
pointer-events-none
pb-1.5;
@apply pointer-events-none absolute top-0 z-10 flex h-full w-20 items-center from-transparent from-10% via-white/80 via-30% to-white to-70% pb-1.5 pt-1;
&.left {
@apply left-0
justify-start
bg-gradient-to-l;
@apply left-0 justify-start bg-gradient-to-l;
}
&.right {
@apply right-0
justify-end
bg-gradient-to-r;
@apply right-0 justify-end bg-gradient-to-r;
}
.arrow-left,
.arrow-right {
@apply w-10
h-9
flex
justify-center
items-center
pointer-events-auto
cursor-pointer
select-none;
@apply pointer-events-auto flex h-9 w-10 cursor-pointer select-none items-center justify-center;
svg {
font-size: 1.5em;
}
@ -269,11 +243,7 @@ onUnmounted(() => {
}
.tabbar-items {
@apply flex
items-center
flex-row
overflow-x-auto
py-0.5;
@apply flex flex-row items-center overflow-x-auto py-0.5;
&::-webkit-scrollbar-track-piece {
background-color: #f8f8f8;
@ -301,15 +271,7 @@ onUnmounted(() => {
}
.tabbar-item {
@apply inline-flex
cursor-pointer
self-center
transition-all
text-sm
justify-center
gap-2
h-9
whitespace-nowrap;
@apply inline-flex h-9 cursor-pointer justify-center gap-2 self-center whitespace-nowrap text-sm transition-all;
.tabbar-item-label,
.tabbar-item-icon {
@ -327,15 +289,12 @@ onUnmounted(() => {
}
.tabbar-item {
@apply px-5
py-1
border-b-gray-100;
@apply border-b-gray-100 px-5 py-1;
border-bottom-width: 2px;
&.tabbar-item-active {
@apply text-secondary
border-b-secondary;
@apply border-b-secondary text-secondary;
}
}
}
@ -347,14 +306,10 @@ onUnmounted(() => {
}
.tabbar-item {
@apply px-6
py-1
opacity-70
rounded-base;
@apply rounded-base px-6 py-1 opacity-70;
&.tabbar-item-active {
@apply bg-gray-100
opacity-100;
@apply bg-gray-100 opacity-100;
}
&:hover {
@ -364,26 +319,17 @@ onUnmounted(() => {
}
&.tabbar-outline {
@apply px-1
py-0.5
bg-gray-100
rounded-base;
@apply rounded-base bg-gray-100 px-1 py-0.5;
.tabbar-items {
@apply gap-1
justify-start;
@apply justify-start gap-1;
}
.tabbar-item {
@apply px-6
py-1
opacity-70
rounded-sm;
@apply rounded-sm px-6 py-1 opacity-70;
&.tabbar-item-active {
@apply bg-white
opacity-100
shadow-sm;
@apply bg-white opacity-100 shadow-sm;
}
&:hover {

View File

@ -1,3 +1,3 @@
export { default as VTabItem } from "./TabItem.vue";
export { default as VTabbar } from "./Tabbar.vue";
export { default as VTabItem } from "./TabItem.vue";
export { default as VTabs } from "./Tabs.vue";

View File

@ -37,37 +37,18 @@ const classes = computed(() => {
</template>
<style lang="scss">
.tag-wrapper {
@apply rounded-base
inline-flex
flex-shrink-0
flex-wrap
box-border
cursor-pointer
text-center
items-center
justify-center
w-auto
align-middle
h-5
text-xs
border
border-solid
px-1;
@apply box-border inline-flex h-5 w-auto flex-shrink-0 cursor-pointer flex-wrap items-center justify-center rounded-base border border-solid px-1 text-center align-middle text-xs;
&.tag-default {
border: 1px solid #d9d9d9;
}
&.tag-primary {
@apply text-white
bg-primary
border-primary;
@apply border-primary bg-primary text-white;
}
&.tag-secondary {
@apply text-white
bg-secondary
border-secondary;
@apply border-secondary bg-secondary text-white;
}
&.tag-danger {

View File

@ -139,18 +139,18 @@ defineExpose({ close });
</template>
<style lang="scss">
.toast-container {
@apply fixed pointer-events-none flex z-[9999] flex-col box-border transition-all w-full left-0 top-0 items-center justify-center p-4 gap-3;
@apply pointer-events-none fixed left-0 top-0 z-[9999] box-border flex w-full flex-col items-center justify-center gap-3 p-4 transition-all;
.toast-wrapper {
@apply inline-block max-w-xs pointer-events-auto relative;
@apply pointer-events-auto relative inline-block max-w-xs;
}
.toast-body {
@apply cursor-pointer flex items-center px-2.5 py-2 overflow-hidden break-all bg-white shadow hover:shadow-md transition-all rounded gap-2;
@apply flex cursor-pointer items-center gap-2 overflow-hidden break-all rounded bg-white px-2.5 py-2 shadow transition-all hover:shadow-md;
}
.toast-content {
@apply text-sm flex flex-col gap-1;
@apply flex flex-col gap-1 text-sm;
}
.toast-description {
@ -158,11 +158,11 @@ defineExpose({ close });
}
.toast-control {
@apply text-gray-600 hover:text-gray-900 transition-all cursor-pointer rounded-full hover:bg-gray-100 p-0.5;
@apply cursor-pointer rounded-full p-0.5 text-gray-600 transition-all hover:bg-gray-100 hover:text-gray-900;
}
.toast-count {
@apply bg-red-500 rounded-full absolute -right-1 -top-1 w-4 h-4 flex items-center justify-center;
@apply absolute -right-1 -top-1 flex h-4 w-4 items-center justify-center rounded-full bg-red-500;
span {
@apply text-[0.7rem] text-white;

View File

@ -1,12 +1,12 @@
import { Meta } from '@storybook/blocks';
import Code from './assets/code-brackets.svg';
import Colors from './assets/colors.svg';
import Comments from './assets/comments.svg';
import Direction from './assets/direction.svg';
import Flow from './assets/flow.svg';
import Plugin from './assets/plugin.svg';
import Repo from './assets/repo.svg';
import StackAlt from './assets/stackalt.svg';
import { Meta } from "@storybook/blocks";
import Code from "./assets/code-brackets.svg";
import Colors from "./assets/colors.svg";
import Comments from "./assets/comments.svg";
import Direction from "./assets/direction.svg";
import Flow from "./assets/flow.svg";
import Plugin from "./assets/plugin.svg";
import Repo from "./assets/repo.svg";
import StackAlt from "./assets/stackalt.svg";
<Meta title="Introduction" />
@ -184,14 +184,22 @@ We recommend building UIs with a [**component-driven**](https://componentdriven.
Configure, customize, and extend
</span>
</a>
<a className="link-item" href="https://storybook.js.org/tutorials/" target="_blank">
<a
className="link-item"
href="https://storybook.js.org/tutorials/"
target="_blank"
>
<img src={Direction} alt="direction" />
<span>
<strong>In-depth guides</strong>
Best practices from leading teams
</span>
</a>
<a className="link-item" href="https://github.com/storybookjs/storybook" target="_blank">
<a
className="link-item"
href="https://github.com/storybookjs/storybook"
target="_blank"
>
<img src={Code} alt="code" />
<span>
<strong>GitHub project</strong>
@ -208,6 +216,6 @@ We recommend building UIs with a [**component-driven**](https://componentdriven.
</div>
<div className="tip-wrapper">
<span className="tip">Tip</span>Edit the Markdown in{' '}
<span className="tip">Tip</span>Edit the Markdown in{" "}
<code>stories/Introduction.stories.mdx</code>
</div>

View File

@ -1,11 +1,11 @@
import { fileURLToPath, URL } from "url";
import { defineConfig, type Plugin } from "vite";
import Vue from "@vitejs/plugin-vue";
import VueJsx from "@vitejs/plugin-vue-jsx";
import Icons from "unplugin-icons/vite";
import Dts from "vite-plugin-dts";
import path from "path";
import Icons from "unplugin-icons/vite";
import { defineConfig, type Plugin } from "vite";
import Dts from "vite-plugin-dts";
export default defineConfig({
experimental: {

View File

@ -1,5 +1,5 @@
import { fileURLToPath } from "node:url";
import { mergeConfig, defineConfig, configDefaults } from "vitest/config";
import { configDefaults, defineConfig, mergeConfig } from "vitest/config";
import viteConfig from "./vite.config";
export default mergeConfig(

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />

View File

@ -31,7 +31,6 @@
"scripts": {
"build": "vite build --config ./vite.lib.config.ts",
"dev": "vite",
"prettier": "prettier --write './src/**/*.{vue,js,jsx,ts,tsx,css,scss,json,yml,yaml,html}'",
"release": "release-it",
"test:unit:coverage": "vitest run --environment jsdom --coverage",
"test:unit:ui": "vitest --environment jsdom --watch --ui",

View File

@ -1,3 +0,0 @@
module.exports = {
plugins: ["../../prettier.config.cjs"],
};

View File

@ -36,8 +36,8 @@ watch(
<div v-if="editor" class="halo-rich-text-editor">
<editor-bubble-menu :editor="editor" />
<editor-header :editor="editor" />
<div class="h-full flex flex-row w-full overflow-hidden">
<div class="overflow-y-auto flex-1 bg-white relative">
<div class="flex h-full w-full flex-row overflow-hidden">
<div class="relative flex-1 overflow-y-auto bg-white">
<div v-if="$slots.content" class="editor-header-extra">
<slot name="content" />
</div>
@ -50,7 +50,7 @@ watch(
</div>
<div
v-if="$slots.extra"
class="h-full hidden sm:!block w-72 flex-shrink-0 flex-none"
class="hidden h-full w-72 flex-none flex-shrink-0 sm:!block"
>
<slot name="extra"></slot>
</div>

View File

@ -71,7 +71,7 @@ const shouldShow = (
:default-animation="bubbleMenu.defaultAnimation"
>
<div
class="bubble-menu bg-white flex items-center rounded-md p-1 border shadow space-x-1"
class="bubble-menu flex items-center space-x-1 rounded-md border bg-white p-1 shadow"
>
<template v-if="bubbleMenu.items">
<template

View File

@ -59,16 +59,16 @@ function getToolboxItemsFromExtensions() {
</script>
<template>
<div
class="editor-header py-1 space-x-1 px-1 overflow-auto border-b shadow-sm bg-white text-center"
class="editor-header space-x-1 overflow-auto border-b bg-white px-1 py-1 text-center shadow-sm"
>
<div class="h-full inline-flex items-center">
<div class="inline-flex h-full items-center">
<VMenu>
<button class="p-1.5 rounded-md hover:bg-gray-100" tabindex="-1">
<button class="rounded-md p-1.5 hover:bg-gray-100" tabindex="-1">
<MdiPlusCircle class="text-[#4CCBA0]" />
</button>
<template #popper>
<div
class="relative rounded-md bg-white overflow-hidden shadow w-56 p-1 max-h-96 overflow-y-auto space-y-1.5"
class="relative max-h-96 w-56 space-y-1.5 overflow-hidden overflow-y-auto rounded-md bg-white p-1 shadow"
>
<component
:is="toolboxItem.component"
@ -80,7 +80,7 @@ function getToolboxItemsFromExtensions() {
</div>
</template>
</VMenu>
<div class="h-5 bg-gray-100 w-[1px] !mx-1"></div>
<div class="!mx-1 h-5 w-[1px] bg-gray-100"></div>
<div
v-for="(item, index) in getToolbarItemsFromExtensions()"
:key="index"
@ -106,7 +106,7 @@ function getToolboxItemsFromExtensions() {
/>
<template #popper>
<div
class="relative rounded-md bg-white overflow-hidden shadow w-56 p-1 max-h-96 overflow-y-auto space-y-1.5"
class="relative max-h-96 w-56 space-y-1.5 overflow-hidden overflow-y-auto rounded-md bg-white p-1 shadow"
>
<component
v-bind="child.props"

View File

@ -27,7 +27,7 @@ withDefaults(
<style lang="scss">
.editor-block__actions-button {
@apply p-1.5 bg-gray-50 rounded-md cursor-pointer hover:bg-gray-200;
@apply cursor-pointer rounded-md bg-gray-50 p-1.5 hover:bg-gray-200;
&--selected {
@apply bg-gray-200;

View File

@ -33,6 +33,6 @@ const value = computed({
<style lang="scss">
.editor-block__actions-input {
@apply bg-gray-50 rounded-md hover:bg-gray-100 block px-2 w-32 py-1 text-sm text-gray-900 border border-gray-300 focus:ring-blue-500 focus:border-blue-500;
@apply block w-32 rounded-md border border-gray-300 bg-gray-50 px-2 py-1 text-sm text-gray-900 hover:bg-gray-100 focus:border-blue-500 focus:ring-blue-500;
}
</style>

View File

@ -4,7 +4,7 @@
<style>
.editor-block__actions-separator {
@apply h-5 bg-slate-200 mx-1.5;
@apply mx-1.5 h-5 bg-slate-200;
width: 1px;
}
</style>

View File

@ -41,7 +41,7 @@ function handleInsertNewLine() {
<slot name="content"></slot>
</div>
<div
class="invisible group-hover:visible pb-2 absolute -top-12 right-0"
class="invisible absolute -top-12 right-0 pb-2 group-hover:visible"
:class="{ '!visible': selected }"
>
<div class="editor-block__actions">
@ -77,12 +77,11 @@ function handleInsertNewLine() {
@apply relative my-9;
&__content {
@apply transition-all
rounded;
@apply rounded transition-all;
}
&__actions {
@apply p-1 flex flex-row rounded-lg border gap-0.5 items-center bg-gray-100 h-11 shadow-lg;
@apply flex h-11 flex-row items-center gap-0.5 rounded-lg border bg-gray-100 p-1 shadow-lg;
}
&:hover & {

View File

@ -55,14 +55,14 @@ const handleBubbleItemClick = (editor: Editor) => {
}"
:class="{ 'bg-gray-200 !text-black': isActive({ editor }) }"
:title="title"
class="text-gray-600 text-lg hover:bg-gray-100 p-2 rounded-md"
class="rounded-md p-2 text-lg text-gray-600 hover:bg-gray-100"
@click="handleBubbleItemClick(editor)"
>
<component :is="icon" :style="iconStyle" class="w-5 h-5" />
<component :is="icon" :style="iconStyle" class="h-5 w-5" />
</button>
<template #popper>
<div
class="relative rounded-md bg-white overflow-hidden shadow w-96 p-1 max-h-72 overflow-y-auto"
class="relative max-h-72 w-96 overflow-hidden overflow-y-auto rounded-md bg-white p-1 shadow"
>
<KeepAlive>
<component :is="componentRef" v-bind="props"></component>

View File

@ -238,14 +238,14 @@ export class BubbleMenuView {
const placement = this.tippyOptions?.placement
? this.tippyOptions?.placement
: isNodeSelection(selection)
? ACTIVE_BUBBLE_MENUS.length > 1
? "bottom"
: "top"
: this.tippy?.props.fixed
? "bottom-start"
: Math.abs(cursorAt - to) <= Math.abs(cursorAt - from)
? "bottom-start"
: "top-start";
? ACTIVE_BUBBLE_MENUS.length > 1
? "bottom"
: "top"
: this.tippy?.props.fixed
? "bottom-start"
: Math.abs(cursorAt - to) <= Math.abs(cursorAt - from)
? "bottom-start"
: "top-start";
const otherBubbleMenus = ACTIVE_BUBBLE_MENUS.filter(
(instance) =>
@ -258,8 +258,8 @@ export class BubbleMenuView {
let offsetY = otherBubbleMenus.length
? otherBubbleMenus.reduce((prev, instance, currentIndex, array) => {
const prevY = array[currentIndex - 1]
? array[currentIndex - 1]?.popperInstance?.state?.modifiersData
?.popperOffsets?.y ?? 0
? (array[currentIndex - 1]?.popperInstance?.state?.modifiersData
?.popperOffsets?.y ?? 0)
: 0;
const currentY =
instance?.popperInstance?.state?.modifiersData?.popperOffsets?.y ??
@ -272,7 +272,7 @@ export class BubbleMenuView {
return prev;
}, 0)
: offset?.[1] ?? 10;
: (offset?.[1] ?? 10);
if (!offsetY) {
offsetY = 10;
}

View File

@ -87,7 +87,7 @@ function onColorChange(color: Payload) {
v-for="item in getColors()"
:key="item.color"
:style="{ backgroundColor: item.color }"
class="h-5 w-5 rounded-sm cursor-pointer hover:ring-1 ring-offset-1 ring-gray-300"
class="h-5 w-5 cursor-pointer rounded-sm ring-gray-300 ring-offset-1 hover:ring-1"
:title="item.name"
@click="handleSetColor(item.color)"
></div>
@ -96,7 +96,7 @@ function onColorChange(color: Payload) {
<VDropdown placement="right">
<div class="p-1">
<div
class="flex items-center rounded cursor-pointer hover:bg-gray-100 p-1 justify-between"
class="flex cursor-pointer items-center justify-between rounded p-1 hover:bg-gray-100"
>
<div class="inline-flex items-center gap-2">
<MdiPalette />

View File

@ -32,7 +32,7 @@ withDefaults(
{ 'cursor-not-allowed opacity-70': disabled },
{ 'hover:bg-gray-100': !disabled },
]"
class="inline-flex items-center space-x-1 p-1.5 rounded-md"
class="inline-flex items-center space-x-1 rounded-md p-1.5"
:disabled="disabled"
tabindex="-1"
@click="action"

View File

@ -28,15 +28,15 @@ const action = () => {
<div
:class="[
{ '!bg-gray-100': isActive },
{ 'cursor-not-allowed opacity-70 ': disabled },
{ 'cursor-not-allowed opacity-70': disabled },
{ 'hover:bg-gray-100': !disabled },
]"
class="flex flex-row items-center rounded gap-3 py-1 px-1.5 group cursor-pointer"
class="group flex cursor-pointer flex-row items-center gap-3 rounded px-1.5 py-1"
@click="action"
>
<component
:is="icon"
class="bg-gray-100 p-1.5 rounded w-7 h-7"
class="h-7 w-7 rounded bg-gray-100 p-1.5"
:class="[
{ '!bg-white': isActive },
{ 'group-hover:bg-white': !disabled },
@ -45,7 +45,7 @@ const action = () => {
<span
class="text-sm text-gray-600"
:class="[
{ '!text-gray-900 !font-medium': isActive },
{ '!font-medium !text-gray-900': isActive },
{ 'group-hover:font-medium group-hover:text-gray-900': !disabled },
]"
>

View File

@ -26,12 +26,12 @@ const action = () => {
<template>
<div
class="flex flex-row items-center rounded gap-3 py-1 px-1.5 group cursor-pointer hover:bg-gray-100"
class="group flex cursor-pointer flex-row items-center gap-3 rounded px-1.5 py-1 hover:bg-gray-100"
@click="action"
>
<component
:is="icon"
class="bg-gray-100 p-1.5 rounded w-7 h-7 group-hover:bg-white"
class="h-7 w-7 rounded bg-gray-100 p-1.5 group-hover:bg-white"
/>
<div class="flex flex-col gap-0.5">
<span

View File

@ -39,13 +39,13 @@ onMounted(() => {
<template>
<node-view-wrapper as="div" class="inline-block w-full">
<div
class="inline-block overflow-hidden transition-all text-center relative h-full w-full"
class="relative inline-block h-full w-full overflow-hidden text-center transition-all"
>
<div v-if="!src" class="p-1.5">
<input
ref="inputRef"
v-model.lazy="src"
class="block px-2 w-full py-1.5 text-sm text-gray-900 border border-gray-300 rounded-md bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
class="block w-full rounded-md border border-gray-300 bg-gray-50 px-2 py-1.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500"
:placeholder="i18n.global.t('editor.common.placeholder.link_input')"
tabindex="-1"
@focus="handleSetFocus"

View File

@ -32,6 +32,6 @@ const src = computed({
<input
v-model.lazy="src"
:placeholder="i18n.global.t('editor.common.placeholder.link_input')"
class="bg-gray-50 rounded-md hover:bg-gray-100 block px-2 w-full py-1.5 text-sm text-gray-900 border border-gray-300 focus:ring-blue-500 focus:border-blue-500"
class="block w-full rounded-md border border-gray-300 bg-gray-50 px-2 py-1.5 text-sm text-gray-900 hover:bg-gray-100 focus:border-blue-500 focus:ring-blue-500"
/>
</template>

View File

@ -151,17 +151,17 @@ const handleScrollIntoView = () => {
<div class="relative inline-block w-full" @keydown="handleOptionKeydown">
<div class="h-8">
<div
class="select-input w-full h-full grid items-center text-sm rounded-md px-3 cursor-pointer box-border"
class="select-input box-border grid h-full w-full cursor-pointer items-center rounded-md px-3 text-sm"
:class="{
'bg-white': isFocus,
'border-[1px]': isFocus,
}"
>
<span class="absolute top-0 bottom-0">
<span class="absolute bottom-0 top-0">
<input
ref="inputRef"
v-model="inputValue"
class="appearance-none bg-transparent h-full ps-0 pe-0 border-none outline-none m-0 p-0 cursor-auto"
class="m-0 h-full cursor-auto appearance-none border-none bg-transparent p-0 pe-0 ps-0 outline-none"
:placeholder="isFocus ? displayLabel : ''"
@focus="handleInputFocus"
@blur="handleInputBlur"
@ -185,7 +185,7 @@ const handleScrollIntoView = () => {
v-for="(option, index) in filterOptions"
:key="option.value"
:index="index"
class="w-full h-8 flex items-center rounded-md text-base px-3 py-1 hover:bg-zinc-100"
class="flex h-8 w-full items-center rounded-md px-3 py-1 text-base hover:bg-zinc-100"
:class="{
'bg-zinc-200': option.value === value,
'bg-zinc-100': selectedIndex === index,
@ -199,7 +199,7 @@ const handleScrollIntoView = () => {
</template>
<template v-else>
<div
class="w-full h-8 flex items-center rounded-md text-base px-3 py-1"
class="flex h-8 w-full items-center rounded-md px-3 py-1 text-base"
>
<span class="flex-1 text-ellipsis text-sm">No options</span>
</div>

View File

@ -97,19 +97,19 @@ const handleCopyCode = () => {
<template>
<node-view-wrapper
as="div"
class="code-node border-[1px] rounded mt-3 overflow-hidden"
class="code-node mt-3 overflow-hidden rounded border-[1px]"
>
<div
contenteditable="false"
class="bg-neutral-100 border-b-[1px] border-b-gray-100 py-1 flex items-center justify-between"
class="flex items-center justify-between border-b-[1px] border-b-gray-100 bg-neutral-100 py-1"
>
<div
class="flex-1 flex items-center pl-3"
class="flex flex-1 items-center pl-3"
@click.self="collapsed ? (collapsed = false) : null"
>
<div class="pr-3 flex items-center">
<div class="flex items-center pr-3">
<div
class="w-8 h-8 cursor-pointer rounded flex items-center justify-center hover:bg-zinc-200"
class="flex h-8 w-8 cursor-pointer items-center justify-center rounded hover:bg-zinc-200"
@click.stop="collapsed = !collapsed"
>
<RiArrowRightSFill v-if="collapsed" />
@ -134,19 +134,19 @@ const handleCopyCode = () => {
>
</CodeBlockSelect>
</div>
<div class="pr-3 flex items-center">
<div class="flex items-center pr-3">
<div
v-tooltip="
ready
? i18n.global.t('editor.common.codeblock.copy_code')
: i18n.global.t('editor.common.codeblock.copy_code_success')
"
class="w-8 h-8 cursor-pointer rounded flex items-center justify-center"
class="flex h-8 w-8 cursor-pointer items-center justify-center rounded"
:class="{ 'hover:bg-zinc-200': ready }"
@click="handleCopyCode"
>
<IconCheckboxCircle v-if="!ready" class="w-4 h-4 text-green-500" />
<BxBxsCopy v-else class="w-4 h-4 text-gray-500" />
<IconCheckboxCircle v-if="!ready" class="h-4 w-4 text-green-500" />
<BxBxsCopy v-else class="h-4 w-4 text-gray-500" />
</div>
</div>
</div>

View File

@ -19,10 +19,10 @@ import {
type Range,
} from "@/tiptap/vue-3";
import { deleteNode } from "@/utils";
import TiptapCodeBlock from "@tiptap/extension-code-block";
import { markRaw } from "vue";
import MdiCodeBracesBox from "~icons/mdi/code-braces-box";
import CodeBlockViewRenderer from "./CodeBlockViewRenderer.vue";
import TiptapCodeBlock from "@tiptap/extension-code-block";
declare module "@/tiptap" {
interface Commands<ReturnType> {

View File

@ -1,2 +1,2 @@
export { default as ExtensionCodeBlock } from "./code-block";
export * from "./code-block";
export { default as ExtensionCodeBlock } from "./code-block";

View File

@ -32,11 +32,11 @@ function handleUnsetColor() {
<template #prefix>
<div class="p-1">
<div
class="flex items-center gap-2 rounded cursor-pointer hover:bg-gray-100 p-1"
class="flex cursor-pointer items-center gap-2 rounded p-1 hover:bg-gray-100"
@click="handleUnsetColor"
>
<div
class="h-5 w-5 rounded-sm cursor-pointer hover:ring-1 ring-offset-1 ring-gray-300 bg-black"
class="h-5 w-5 cursor-pointer rounded-sm bg-black ring-gray-300 ring-offset-1 hover:ring-1"
></div>
<span class="text-xs text-gray-600">
{{ i18n.global.t("editor.common.button.restore_default") }}

View File

@ -42,11 +42,11 @@ function handleUnsetColor() {
<template #prefix>
<div class="p-1">
<div
class="flex items-center gap-2 rounded cursor-pointer hover:bg-gray-100 p-1"
class="flex cursor-pointer items-center gap-2 rounded p-1 hover:bg-gray-100"
@click="handleUnsetColor"
>
<div
class="h-5 w-5 rounded-sm cursor-pointer hover:ring-1 ring-offset-1 ring-gray-300 bg-black"
class="h-5 w-5 cursor-pointer rounded-sm bg-black ring-gray-300 ring-offset-1 hover:ring-1"
></div>
<span class="text-xs text-gray-600">
{{ i18n.global.t("editor.common.button.restore_default") }}

View File

@ -1,9 +1,9 @@
import TextStyle from "@/extensions/text-style";
import { i18n } from "@/locales";
import type { Editor } from "@/tiptap/vue-3";
import type { ExtensionOptions } from "@/types";
import type { ColorOptions } from "@tiptap/extension-color";
import TiptapColor from "@tiptap/extension-color";
import TextStyle from "@/extensions/text-style";
import { markRaw } from "vue";
import MdiFormatColor from "~icons/mdi/format-color";
import ColorToolbarItem from "./ColorToolbarItem.vue";

View File

@ -95,7 +95,7 @@ defineExpose({
>
<component :is="item.icon" class="command-icon group-hover:!bg-white" />
<span
class="command-title group-hover:text-gray-900 group-hover:font-medium"
class="command-title group-hover:font-medium group-hover:text-gray-900"
>
{{ i18n.global.t(item.title) }}
</span>
@ -110,18 +110,10 @@ defineExpose({
</template>
<style lang="scss">
.command-items {
@apply relative
rounded-md
bg-white
overflow-hidden
shadow
w-52
p-1
max-h-72
overflow-y-auto;
@apply relative max-h-72 w-52 overflow-hidden overflow-y-auto rounded-md bg-white p-1 shadow;
.command-item {
@apply flex flex-row items-center rounded gap-4 p-1;
@apply flex flex-row items-center gap-4 rounded p-1;
&.is-selected {
@apply bg-gray-100;
@ -131,22 +123,21 @@ defineExpose({
}
.command-title {
@apply text-gray-900 font-medium;
@apply font-medium text-gray-900;
}
}
.command-icon {
@apply bg-gray-100 p-1 rounded w-6 h-6;
@apply h-6 w-6 rounded bg-gray-100 p-1;
}
.command-title {
@apply text-xs
text-gray-600;
@apply text-xs text-gray-600;
}
}
.command-empty {
@apply flex justify-center items-center p-1 text-xs text-gray-600;
@apply flex items-center justify-center p-1 text-xs text-gray-600;
}
}
</style>

View File

@ -376,8 +376,8 @@ const dropPoint = (doc: Node, pos: number, slice: Slice) => {
dep == $pos.depth
? 0
: $pos.pos <= ($pos.start(dep + 1) + $pos.end(dep + 1)) / 2
? -1
: 1;
? -1
: 1;
const insertPos = $pos.index(dep) + (bias > 0 ? 1 : 0);
const parent = $pos.node(dep);
let fits = false;
@ -396,8 +396,8 @@ const dropPoint = (doc: Node, pos: number, slice: Slice) => {
return bias == 0
? $pos.pos
: bias < 0
? $pos.before(dep + 1)
: $pos.after(dep + 1);
? $pos.before(dep + 1)
: $pos.after(dep + 1);
}
}
}

View File

@ -1,7 +1,7 @@
import { ToolbarItem, ToolbarSubItem } from "@/components";
import TextStyle from "@/extensions/text-style";
import { i18n } from "@/locales";
import { Extension, type Editor } from "@/tiptap/vue-3";
import TextStyle from "@/extensions/text-style";
import { markRaw } from "vue";
import MdiFormatSize from "~icons/mdi/format-size";

View File

@ -33,7 +33,7 @@ function handleUnsetColor() {
<template #prefix>
<div class="p-1">
<div
class="flex items-center gap-2 rounded cursor-pointer hover:bg-gray-100 p-1"
class="flex cursor-pointer items-center gap-2 rounded p-1 hover:bg-gray-100"
@click="handleUnsetColor"
>
<div class="inline-flex items-center gap-2">
@ -46,11 +46,11 @@ function handleUnsetColor() {
</div>
<div class="p-1">
<div
class="flex items-center gap-2 rounded cursor-pointer hover:bg-gray-100 p-1"
class="flex cursor-pointer items-center gap-2 rounded p-1 hover:bg-gray-100"
@click="handleSetColor()"
>
<div
class="h-5 w-5 rounded-sm cursor-pointer hover:ring-1 ring-offset-1 ring-gray-300"
class="h-5 w-5 cursor-pointer rounded-sm ring-gray-300 ring-offset-1 hover:ring-1"
:style="{ 'background-color': '#fff8c5' }"
></div>
<span class="text-xs text-gray-600">

View File

@ -44,7 +44,7 @@ function handleUnsetColor() {
<template #prefix>
<div class="p-1">
<div
class="flex items-center gap-2 rounded cursor-pointer hover:bg-gray-100 p-1"
class="flex cursor-pointer items-center gap-2 rounded p-1 hover:bg-gray-100"
@click="handleUnsetColor"
>
<div class="inline-flex items-center gap-2">
@ -57,11 +57,11 @@ function handleUnsetColor() {
</div>
<div class="p-1">
<div
class="flex items-center gap-2 rounded cursor-pointer hover:bg-gray-100 p-1"
class="flex cursor-pointer items-center gap-2 rounded p-1 hover:bg-gray-100"
@click="handleSetColor()"
>
<div
class="h-5 w-5 rounded-sm cursor-pointer hover:ring-1 ring-offset-1 ring-gray-300"
class="h-5 w-5 cursor-pointer rounded-sm ring-gray-300 ring-offset-1 hover:ring-1"
:style="{ 'background-color': '#fff8c5' }"
></div>
<span class="text-xs text-gray-600">

View File

@ -31,6 +31,6 @@ const src = computed({
<input
v-model.lazy="src"
:placeholder="i18n.global.t('editor.common.placeholder.link_input')"
class="bg-gray-50 rounded-md hover:bg-gray-100 block px-2 w-full py-1.5 text-sm text-gray-900 border border-gray-300 focus:ring-blue-500 focus:border-blue-500"
class="block w-full rounded-md border border-gray-300 bg-gray-50 px-2 py-1.5 text-sm text-gray-900 hover:bg-gray-100 focus:border-blue-500 focus:ring-blue-500"
/>
</template>

View File

@ -38,7 +38,7 @@ onMounted(() => {
<template>
<node-view-wrapper as="div" class="inline-block w-full">
<div
class="inline-block overflow-hidden transition-all text-center relative h-full max-w-full"
class="relative inline-block h-full max-w-full overflow-hidden text-center transition-all"
:style="{
width: node.attrs.width,
}"
@ -47,7 +47,7 @@ onMounted(() => {
<input
ref="inputRef"
v-model.lazy="src"
class="block px-2 w-full py-1.5 text-sm text-gray-900 border border-gray-300 rounded-md bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
class="block w-full rounded-md border border-gray-300 bg-gray-50 px-2 py-1.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500"
:placeholder="i18n.global.t('editor.common.placeholder.link_input')"
tabindex="-1"
@focus="handleSetFocus"

View File

@ -32,6 +32,6 @@ const alt = computed({
<input
v-model.lazy="alt"
:placeholder="i18n.global.t('editor.common.placeholder.alt_input')"
class="bg-gray-50 rounded-md hover:bg-gray-100 block px-2 w-full py-1.5 text-sm text-gray-900 border border-gray-300 focus:ring-blue-500 focus:border-blue-500"
class="block w-full rounded-md border border-gray-300 bg-gray-50 px-2 py-1.5 text-sm text-gray-900 hover:bg-gray-100 focus:border-blue-500 focus:ring-blue-500"
/>
</template>

View File

@ -1,8 +1,8 @@
<script setup lang="ts">
import { ExtensionImage, ExtensionLink } from "@/extensions";
import { i18n } from "@/locales";
import type { Editor } from "@/tiptap/vue-3";
import { computed, type Component } from "vue";
import { ExtensionLink, ExtensionImage } from "@/extensions";
const props = defineProps<{
editor: Editor;
@ -41,13 +41,13 @@ const target = computed({
<input
v-model.lazy="href"
:placeholder="i18n.global.t('editor.common.placeholder.alt_href')"
class="bg-gray-50 rounded-md hover:bg-gray-100 block px-2 w-full py-1.5 text-sm text-gray-900 border border-gray-300 focus:ring-blue-500 focus:border-blue-500"
class="block w-full rounded-md border border-gray-300 bg-gray-50 px-2 py-1.5 text-sm text-gray-900 hover:bg-gray-100 focus:border-blue-500 focus:ring-blue-500"
/>
<label class="inline-flex items-center mt-2">
<label class="mt-2 inline-flex items-center">
<input
v-model="target"
type="checkbox"
class="form-checkbox text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
class="form-checkbox rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<span class="ml-2 text-sm text-gray-500">
{{ i18n.global.t("editor.extensions.link.open_in_new_window") }}

View File

@ -32,6 +32,6 @@ const src = computed({
<input
v-model.lazy="src"
:placeholder="i18n.global.t('editor.common.placeholder.link_input')"
class="bg-gray-50 rounded-md hover:bg-gray-100 block px-2 w-full py-1.5 text-sm text-gray-900 border border-gray-300 focus:ring-blue-500 focus:border-blue-500"
class="block w-full rounded-md border border-gray-300 bg-gray-50 px-2 py-1.5 text-sm text-gray-900 hover:bg-gray-100 focus:border-blue-500 focus:ring-blue-500"
/>
</template>

View File

@ -95,11 +95,11 @@ onMounted(() => {
<template>
<node-view-wrapper as="div" class="inline-block w-full">
<div v-if="!src" class="p-1.5 w-full">
<div v-if="!src" class="w-full p-1.5">
<input
ref="inputRef"
v-model.lazy="src"
class="block px-2 w-full py-1.5 text-sm text-gray-900 border border-gray-300 rounded-md bg-gray-50 focus:ring-blue-500 focus:border-blue-500"
class="block w-full rounded-md border border-gray-300 bg-gray-50 px-2 py-1.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500"
:placeholder="i18n.global.t('editor.common.placeholder.link_input')"
tabindex="-1"
@focus="handleSetFocus"
@ -108,9 +108,9 @@ onMounted(() => {
<div
v-else
ref="resizeRef"
class="resize-x inline-block overflow-hidden text-center relative rounded-md max-w-full"
class="relative inline-block max-w-full resize-x overflow-hidden rounded-md text-center"
:class="{
'ring-2 rounded': selected,
'rounded ring-2': selected,
}"
:style="{
width: node.attrs.width,
@ -122,7 +122,7 @@ onMounted(() => {
:title="node.attrs.title"
:alt="alt"
:href="href"
class="w-full h-full"
class="h-full w-full"
@load="onImageLoaded"
/>
</div>

View File

@ -28,11 +28,11 @@ import ExtensionTextAlign from "./text-align";
import ExtensionUnderline from "./underline";
// Custom extensions
import ExtensionTextStyle from "@/extensions/text-style";
import {
ExtensionCodeBlock,
type ExtensionCodeBlockOptions,
} from "@/extensions/code-block";
import ExtensionTextStyle from "@/extensions/text-style";
import { ExtensionCommands } from "../extensions/commands-menu";
import ExtensionAudio from "./audio";
import ExtensionClearFormat from "./clear-format";
@ -110,6 +110,7 @@ const allExtensions = [
];
export {
allExtensions,
ExtensionAudio,
ExtensionBlockquote,
ExtensionBold,
@ -156,7 +157,6 @@ export {
ExtensionUnderline,
ExtensionVideo,
RangeSelection,
allExtensions,
};
export type { ExtensionCodeBlockOptions };

Some files were not shown because too many files have changed in this diff Show More