docs(media): add standalone package guide
This commit is contained in:
@@ -31,8 +31,8 @@ const packageDefinitions: readonly PackageDefinition[] = [
|
|||||||
key: "blocks",
|
key: "blocks",
|
||||||
label: "Blocks",
|
label: "Blocks",
|
||||||
description: {
|
description: {
|
||||||
zh: "构建应用外壳,并接入导航、通知、聊天、媒体和外观控制。",
|
zh: "构建应用外壳,并接入导航、通知、聊天和外观控制。",
|
||||||
us: "Build an application shell and add navigation, notifications, chat, media, and appearance controls.",
|
us: "Build an application shell and add navigation, notifications, chat, and appearance controls.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -51,6 +51,14 @@ const packageDefinitions: readonly PackageDefinition[] = [
|
|||||||
us: "Build a rich-text editor progressively from its root and content surface to custom actions and media.",
|
us: "Build a rich-text editor progressively from its root and content surface to custom actions and media.",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "media",
|
||||||
|
label: "Media",
|
||||||
|
description: {
|
||||||
|
zh: "通过存储 Adapter 构建媒体浏览、上传、目录管理和资源选择流程。",
|
||||||
|
us: "Build media browsing, uploads, folder management, and asset selection with a storage adapter.",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: "preferences",
|
key: "preferences",
|
||||||
label: "Preferences",
|
label: "Preferences",
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
---
|
|
||||||
title: Media library
|
|
||||||
description: Supply a storage adapter and add browsing, upload, folders, and asset selection.
|
|
||||||
order: 21
|
|
||||||
toc:
|
|
||||||
- id: implement-the-adapter
|
|
||||||
title: Implement the adapter
|
|
||||||
- id: provide-media
|
|
||||||
title: Provide media
|
|
||||||
- id: selection-flows
|
|
||||||
title: Selection flows
|
|
||||||
---
|
|
||||||
|
|
||||||
## Implement the adapter {#implement-the-adapter}
|
|
||||||
|
|
||||||
`MediaAdapter` is the media feature's complete persistence boundary. Implement its query, upload, folder, update, and delete operations with the product's storage service.
|
|
||||||
|
|
||||||
## Provide media {#provide-media}
|
|
||||||
|
|
||||||
Mount the adapter once around the media surfaces:
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import { MediaLibrary, MediaProvider } from "@workspace/blocks/media"
|
|
||||||
|
|
||||||
;<MediaProvider adapter={mediaAdapter} notify={showNotice}>
|
|
||||||
<MediaLibrary />
|
|
||||||
</MediaProvider>
|
|
||||||
```
|
|
||||||
|
|
||||||
The optional `notify` callback translates operational results into the application's toast or notification system.
|
|
||||||
|
|
||||||
## Selection flows {#selection-flows}
|
|
||||||
|
|
||||||
Use `MediaPickerDialog` for single or multiple asset selection. `readMediaDimensions`, `formatMediaFileSize`, and `defaultMediaReference` cover the common presentation work around uploads and previews.
|
|
||||||
@@ -33,7 +33,7 @@ Import the block stylesheet once from the application entry:
|
|||||||
import "@workspace/blocks/globals.css"
|
import "@workspace/blocks/globals.css"
|
||||||
```
|
```
|
||||||
|
|
||||||
Keep feature imports on their explicit subpaths. For example, importing `@workspace/blocks/media` does not pull chat into the same module graph.
|
Keep feature imports on their explicit subpaths. For example, importing `@workspace/blocks/notifications` does not pull chat into the same module graph. Media workflows are provided separately by `@workspace/media`.
|
||||||
|
|
||||||
## Application providers {#application-providers}
|
## Application providers {#application-providers}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ toc:
|
|||||||
|
|
||||||
## What you will build {#what-you-will-build}
|
## What you will build {#what-you-will-build}
|
||||||
|
|
||||||
This tutorial builds an application shell step by step. You will begin with the shared layout, connect navigation, then add notifications, chat, media, and appearance preferences.
|
This tutorial builds an application shell step by step. You will begin with the shared layout, connect navigation, then add notifications, chat, and appearance preferences.
|
||||||
|
|
||||||
By the end, the application owns its data and business rules while `@workspace/blocks` owns the reusable presentation and interaction patterns.
|
By the end, the application owns its data and business rules while `@workspace/blocks` owns the reusable presentation and interaction patterns.
|
||||||
|
|
||||||
@@ -29,5 +29,5 @@ Blocks sit above `@workspace/ui`. They combine low-level components into feature
|
|||||||
2. Create the application shell.
|
2. Create the application shell.
|
||||||
3. Define navigation and route state.
|
3. Define navigation and route state.
|
||||||
4. Connect notifications.
|
4. Connect notifications.
|
||||||
5. Add chat and media workflows.
|
5. Add chat workflows.
|
||||||
6. Finish with persistent appearance controls.
|
6. Finish with persistent appearance controls.
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
---
|
|
||||||
title: 媒体库
|
|
||||||
description: 提供存储 Adapter,并加入浏览、上传、文件夹和资源选择能力。
|
|
||||||
order: 21
|
|
||||||
toc:
|
|
||||||
- id: implement-the-adapter
|
|
||||||
title: 实现 Adapter
|
|
||||||
- id: provide-media
|
|
||||||
title: 提供媒体能力
|
|
||||||
- id: selection-flows
|
|
||||||
title: 选择流程
|
|
||||||
---
|
|
||||||
|
|
||||||
## 实现 Adapter {#implement-the-adapter}
|
|
||||||
|
|
||||||
`MediaAdapter` 是媒体功能完整的持久化边界。通过产品存储服务实现查询、上传、文件夹、更新和删除操作。
|
|
||||||
|
|
||||||
## 提供媒体能力 {#provide-media}
|
|
||||||
|
|
||||||
在媒体界面外挂载一次 Adapter:
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
import { MediaLibrary, MediaProvider } from "@workspace/blocks/media"
|
|
||||||
|
|
||||||
;<MediaProvider adapter={mediaAdapter} notify={showNotice}>
|
|
||||||
<MediaLibrary />
|
|
||||||
</MediaProvider>
|
|
||||||
```
|
|
||||||
|
|
||||||
可选的 `notify` 回调把操作结果转换为应用的 Toast 或通知。
|
|
||||||
|
|
||||||
## 选择流程 {#selection-flows}
|
|
||||||
|
|
||||||
单选或多选资源使用 `MediaPickerDialog`。`readMediaDimensions`、`formatMediaFileSize` 和 `defaultMediaReference` 覆盖上传与预览相关的常用展示工作。
|
|
||||||
@@ -33,7 +33,7 @@ Blocks 使用 `@workspace/ui`、React Query 和工作区国际化运行时。工
|
|||||||
import "@workspace/blocks/globals.css"
|
import "@workspace/blocks/globals.css"
|
||||||
```
|
```
|
||||||
|
|
||||||
功能模块应始终从显式子路径导入。例如,导入 `@workspace/blocks/media` 不会把聊天功能加入同一个模块图。
|
功能模块应始终从显式子路径导入。例如,导入 `@workspace/blocks/notifications` 不会把聊天功能加入同一个模块图。媒体工作流由独立的 `@workspace/media` 提供。
|
||||||
|
|
||||||
## 应用 Providers {#application-providers}
|
## 应用 Providers {#application-providers}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ toc:
|
|||||||
|
|
||||||
## 将要构建的内容 {#what-you-will-build}
|
## 将要构建的内容 {#what-you-will-build}
|
||||||
|
|
||||||
本教程会逐步构建一个应用外壳。你将从共享布局开始,接入导航,再添加通知、聊天、媒体和外观偏好。
|
本教程会逐步构建一个应用外壳。你将从共享布局开始,接入导航,再添加通知、聊天和外观偏好。
|
||||||
|
|
||||||
完成后,应用负责数据和业务规则,`@workspace/blocks` 负责可复用的展示与交互模式。
|
完成后,应用负责数据和业务规则,`@workspace/blocks` 负责可复用的展示与交互模式。
|
||||||
|
|
||||||
@@ -29,5 +29,5 @@ Blocks 位于 `@workspace/ui` 之上。它们将底层组件组合成完整功
|
|||||||
2. 创建应用外壳。
|
2. 创建应用外壳。
|
||||||
3. 定义导航和路由状态。
|
3. 定义导航和路由状态。
|
||||||
4. 接入通知。
|
4. 接入通知。
|
||||||
5. 添加聊天和媒体工作流。
|
5. 添加聊天工作流。
|
||||||
6. 使用持久化外观控件完成应用。
|
6. 使用持久化外观控件完成应用。
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
title: Storage adapter
|
||||||
|
description: Connect queries, uploads, mutations, URL resolution, and pagination to product infrastructure.
|
||||||
|
order: 20
|
||||||
|
toc:
|
||||||
|
- id: implement-the-contract
|
||||||
|
title: Implement the contract
|
||||||
|
- id: separate-display-and-reference-urls
|
||||||
|
title: Separate display and reference URLs
|
||||||
|
- id: preserve-query-semantics
|
||||||
|
title: Preserve query semantics
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implement the contract {#implement-the-contract}
|
||||||
|
|
||||||
|
`MediaAdapter` is the package's complete persistence boundary. Implement its asset queries, folder operations, uploads, updates, and deletes with the product's storage service.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import type { MediaAdapter } from "@workspace/media"
|
||||||
|
|
||||||
|
export const mediaAdapter: MediaAdapter = {
|
||||||
|
listAssets: (query) => api.media.list(query),
|
||||||
|
listFolders: () => api.media.listFolders(),
|
||||||
|
upload: (input) => api.media.upload(input),
|
||||||
|
createFolder: (input) => api.media.createFolder(input),
|
||||||
|
updateFolder: (input) => api.media.updateFolder(input),
|
||||||
|
deleteFolder: (id) => api.media.deleteFolder(id),
|
||||||
|
moveAsset: (id, folderId) => api.media.move(id, folderId),
|
||||||
|
renameAsset: (id, name) => api.media.rename(id, name),
|
||||||
|
updateFavorite: (id, favorite) => api.media.favorite(id, favorite),
|
||||||
|
deleteAsset: (id) => api.media.delete(id),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Separate display and reference URLs {#separate-display-and-reference-urls}
|
||||||
|
|
||||||
|
Use `resolveUrl` for short-lived signed URLs or image transformations used while rendering. Use `resolveReference` for the value returned by the picker and stored in another document. When `resolveReference` is absent, images use `defaultMediaReference`, which preserves intrinsic dimensions in the URL.
|
||||||
|
|
||||||
|
## Preserve query semantics {#preserve-query-semantics}
|
||||||
|
|
||||||
|
Treat `MediaAssetQuery` as an immutable request. Apply `allowedKinds`, `filter`, `folder`, and `keyword` before pagination, then return `hasNextPage` based on the filtered result. This keeps desktop and mobile filters consistent.
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
title: Asset picker
|
||||||
|
description: Reuse the media library as a controlled single- or multiple-selection dialog.
|
||||||
|
order: 30
|
||||||
|
toc:
|
||||||
|
- id: open-the-picker
|
||||||
|
title: Open the picker
|
||||||
|
- id: constrain-selection
|
||||||
|
title: Constrain selection
|
||||||
|
- id: consume-results
|
||||||
|
title: Consume results
|
||||||
|
---
|
||||||
|
|
||||||
|
## Open the picker {#open-the-picker}
|
||||||
|
|
||||||
|
`MediaPickerDialog` reuses the same adapter and folder model as the full library:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { MediaPickerDialog } from "@workspace/media"
|
||||||
|
|
||||||
|
;<MediaPickerDialog
|
||||||
|
open={open}
|
||||||
|
onOpenChange={setOpen}
|
||||||
|
onConfirm={(assets) => editor.insertImages(assets)}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Constrain selection {#constrain-selection}
|
||||||
|
|
||||||
|
Pass `allowedKinds={["image"]}` for an image-only workflow. The dialog selects one asset by default; pass `multiple` when the consumer accepts several assets, and provide `initialSelection` when editing an existing value.
|
||||||
|
|
||||||
|
## Consume results {#consume-results}
|
||||||
|
|
||||||
|
The confirmation callback receives complete `MediaAsset` records. Store the adapter-provided reference rather than a temporary preview URL when the result must survive signed-URL expiration.
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
title: Installation and setup
|
||||||
|
description: Add Media, register its catalog, and connect the storage adapter.
|
||||||
|
order: 10
|
||||||
|
toc:
|
||||||
|
- id: add-the-package
|
||||||
|
title: Add the package
|
||||||
|
- id: register-styles-and-catalogs
|
||||||
|
title: Register styles and catalogs
|
||||||
|
- id: provide-media
|
||||||
|
title: Provide media
|
||||||
|
---
|
||||||
|
|
||||||
|
## Add the package {#add-the-package}
|
||||||
|
|
||||||
|
Add Media to the consuming application:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@workspace/media": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Register styles and catalogs {#register-styles-and-catalogs}
|
||||||
|
|
||||||
|
Import the stylesheet once so Tailwind includes utilities used by the package:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import "@workspace/media/globals.css";
|
||||||
|
```
|
||||||
|
|
||||||
|
Add `@workspace/media/locales/{locale}` to the application's internationalization catalog sources.
|
||||||
|
|
||||||
|
## Provide media {#provide-media}
|
||||||
|
|
||||||
|
Mount the adapter once around every media surface that should share storage behavior and notifications:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { MediaLibrary, MediaProvider } from "@workspace/media"
|
||||||
|
|
||||||
|
;<MediaProvider adapter={mediaAdapter} notify={showNotice}>
|
||||||
|
<MediaLibrary />
|
||||||
|
</MediaProvider>
|
||||||
|
```
|
||||||
|
|
||||||
|
The optional `notify` callback turns operation results into the application's toast or notification system.
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
title: Overview
|
||||||
|
description: Understand the Media package, its storage boundary, and the workflows it owns.
|
||||||
|
order: 1
|
||||||
|
toc:
|
||||||
|
- id: package-role
|
||||||
|
title: Package role
|
||||||
|
- id: capabilities
|
||||||
|
title: Capabilities
|
||||||
|
- id: design-boundary
|
||||||
|
title: Design boundary
|
||||||
|
---
|
||||||
|
|
||||||
|
## Package role {#package-role}
|
||||||
|
|
||||||
|
`@workspace/media` provides reusable media-library and asset-picker surfaces. The host application supplies persistence through `MediaAdapter`; Media owns browsing, filtering, pagination, uploads, folders, selection, and asset actions.
|
||||||
|
|
||||||
|
## Capabilities {#capabilities}
|
||||||
|
|
||||||
|
- Browse images and videos with search, filters, folders, favorites, and pagination.
|
||||||
|
- Upload to local or cloud storage targets exposed by the adapter.
|
||||||
|
- Create, rename, nest, and delete organizational folders.
|
||||||
|
- Select one or multiple assets through `MediaPickerDialog`.
|
||||||
|
- Resolve display URLs and stable references independently.
|
||||||
|
- Ship `en-US` and `zh-Hans` message catalogs.
|
||||||
|
|
||||||
|
## Design boundary {#design-boundary}
|
||||||
|
|
||||||
|
Media does not choose an API, database, object store, CDN, or signing strategy. The application implements those decisions behind `MediaAdapter` and can replace them without changing the interface components.
|
||||||
|
|
||||||
|
> Folders classify assets inside the library. They do not need to mirror object-storage paths or change public URLs.
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
---
|
||||||
|
title: 存储 Adapter
|
||||||
|
description: 将查询、上传、变更、URL 解析和分页连接到产品基础设施。
|
||||||
|
order: 20
|
||||||
|
toc:
|
||||||
|
- id: implement-the-contract
|
||||||
|
title: 实现完整契约
|
||||||
|
- id: separate-display-and-reference-urls
|
||||||
|
title: 区分展示与引用 URL
|
||||||
|
- id: preserve-query-semantics
|
||||||
|
title: 保持查询语义
|
||||||
|
---
|
||||||
|
|
||||||
|
## 实现完整契约 {#implement-the-contract}
|
||||||
|
|
||||||
|
`MediaAdapter` 是这个包完整的持久化边界。通过产品的存储服务实现资源查询、目录操作、上传、更新和删除。
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import type { MediaAdapter } from "@workspace/media"
|
||||||
|
|
||||||
|
export const mediaAdapter: MediaAdapter = {
|
||||||
|
listAssets: (query) => api.media.list(query),
|
||||||
|
listFolders: () => api.media.listFolders(),
|
||||||
|
upload: (input) => api.media.upload(input),
|
||||||
|
createFolder: (input) => api.media.createFolder(input),
|
||||||
|
updateFolder: (input) => api.media.updateFolder(input),
|
||||||
|
deleteFolder: (id) => api.media.deleteFolder(id),
|
||||||
|
moveAsset: (id, folderId) => api.media.move(id, folderId),
|
||||||
|
renameAsset: (id, name) => api.media.rename(id, name),
|
||||||
|
updateFavorite: (id, favorite) => api.media.favorite(id, favorite),
|
||||||
|
deleteAsset: (id) => api.media.delete(id),
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 区分展示与引用 URL {#separate-display-and-reference-urls}
|
||||||
|
|
||||||
|
使用 `resolveUrl` 返回渲染时需要的短期签名 URL 或图片转换地址。使用 `resolveReference` 返回选择器写入其他文档的值。未提供 `resolveReference` 时,图片会使用 `defaultMediaReference`,在 URL 中保留固有尺寸。
|
||||||
|
|
||||||
|
## 保持查询语义 {#preserve-query-semantics}
|
||||||
|
|
||||||
|
将 `MediaAssetQuery` 当作不可变请求。在分页前依次应用 `allowedKinds`、`filter`、`folder` 和 `keyword`,然后根据筛选后的结果返回 `hasNextPage`。这样可以保持桌面端与移动端筛选行为一致。
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
title: 资源选择器
|
||||||
|
description: 将媒体库复用为受控的单选或多选对话框。
|
||||||
|
order: 30
|
||||||
|
toc:
|
||||||
|
- id: open-the-picker
|
||||||
|
title: 打开选择器
|
||||||
|
- id: constrain-selection
|
||||||
|
title: 限制选择范围
|
||||||
|
- id: consume-results
|
||||||
|
title: 使用选择结果
|
||||||
|
---
|
||||||
|
|
||||||
|
## 打开选择器 {#open-the-picker}
|
||||||
|
|
||||||
|
`MediaPickerDialog` 会复用完整媒体库相同的 Adapter 和目录模型:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { MediaPickerDialog } from "@workspace/media"
|
||||||
|
|
||||||
|
;<MediaPickerDialog
|
||||||
|
open={open}
|
||||||
|
onOpenChange={setOpen}
|
||||||
|
onConfirm={(assets) => editor.insertImages(assets)}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 限制选择范围 {#constrain-selection}
|
||||||
|
|
||||||
|
图片专用流程传入 `allowedKinds={["image"]}`。对话框默认单选;消费方可以接受多个资源时传入 `multiple`,编辑已有值时通过 `initialSelection` 恢复选择。
|
||||||
|
|
||||||
|
## 使用选择结果 {#consume-results}
|
||||||
|
|
||||||
|
确认回调会收到完整的 `MediaAsset` 记录。如果结果需要在签名 URL 失效后继续使用,应保存 Adapter 提供的稳定引用,而不是临时预览地址。
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
title: 安装与设置
|
||||||
|
description: 添加 Media、注册词典并连接存储 Adapter。
|
||||||
|
order: 10
|
||||||
|
toc:
|
||||||
|
- id: add-the-package
|
||||||
|
title: 添加包
|
||||||
|
- id: register-styles-and-catalogs
|
||||||
|
title: 注册样式与词典
|
||||||
|
- id: provide-media
|
||||||
|
title: 提供媒体能力
|
||||||
|
---
|
||||||
|
|
||||||
|
## 添加包 {#add-the-package}
|
||||||
|
|
||||||
|
在使用方应用中添加 Media:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"@workspace/media": "workspace:*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 注册样式与词典 {#register-styles-and-catalogs}
|
||||||
|
|
||||||
|
导入一次样式表,让 Tailwind 包含 Media 使用的工具类:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import "@workspace/media/globals.css";
|
||||||
|
```
|
||||||
|
|
||||||
|
将 `@workspace/media/locales/{locale}` 加入应用的国际化 catalog sources。
|
||||||
|
|
||||||
|
## 提供媒体能力 {#provide-media}
|
||||||
|
|
||||||
|
在需要共享存储行为和通知方式的媒体界面外统一挂载 Adapter:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { MediaLibrary, MediaProvider } from "@workspace/media"
|
||||||
|
|
||||||
|
;<MediaProvider adapter={mediaAdapter} notify={showNotice}>
|
||||||
|
<MediaLibrary />
|
||||||
|
</MediaProvider>
|
||||||
|
```
|
||||||
|
|
||||||
|
可选的 `notify` 回调会把操作结果接入应用自己的 Toast 或通知系统。
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
title: 概览
|
||||||
|
description: 了解 Media 包、存储边界以及它负责的媒体工作流。
|
||||||
|
order: 1
|
||||||
|
toc:
|
||||||
|
- id: package-role
|
||||||
|
title: 包的职责
|
||||||
|
- id: capabilities
|
||||||
|
title: 功能范围
|
||||||
|
- id: design-boundary
|
||||||
|
title: 设计边界
|
||||||
|
---
|
||||||
|
|
||||||
|
## 包的职责 {#package-role}
|
||||||
|
|
||||||
|
`@workspace/media` 提供可复用的媒体库和资源选择界面。宿主应用通过 `MediaAdapter` 提供持久化能力;Media 负责浏览、筛选、分页、上传、目录、选择和资源操作。
|
||||||
|
|
||||||
|
## 功能范围 {#capabilities}
|
||||||
|
|
||||||
|
- 通过搜索、筛选、目录、收藏和分页浏览图片与视频。
|
||||||
|
- 上传到 Adapter 暴露的本地或云端存储目标。
|
||||||
|
- 创建、重命名、嵌套和删除分类目录。
|
||||||
|
- 通过 `MediaPickerDialog` 单选或多选资源。
|
||||||
|
- 分别解析展示 URL 和稳定引用。
|
||||||
|
- 提供 `en-US` 与 `zh-Hans` 消息词典。
|
||||||
|
|
||||||
|
## 设计边界 {#design-boundary}
|
||||||
|
|
||||||
|
Media 不会替应用选择 API、数据库、对象存储、CDN 或签名策略。应用在 `MediaAdapter` 后实现这些决策,替换实现时无需修改界面组件。
|
||||||
|
|
||||||
|
> 目录只用于媒体库内部分类,不必对应对象存储路径,也不需要改变公开 URL。
|
||||||
@@ -21,4 +21,4 @@ This tutorial installs the styles, introduces component subpaths, builds a small
|
|||||||
|
|
||||||
## UI or Blocks {#ui-or-blocks}
|
## UI or Blocks {#ui-or-blocks}
|
||||||
|
|
||||||
Use UI components when the application owns the workflow. Use `@workspace/blocks` when the interface also needs a complete feature contract such as navigation, media storage, search adapters, or notification queries.
|
Use UI components when the application owns the workflow. Use `@workspace/blocks` for complete application-shell features such as navigation and notifications, and focused packages such as `@workspace/media` or `@workspace/search` for domain workflows.
|
||||||
|
|||||||
@@ -21,4 +21,4 @@ toc:
|
|||||||
|
|
||||||
## UI 还是 Blocks {#ui-or-blocks}
|
## UI 还是 Blocks {#ui-or-blocks}
|
||||||
|
|
||||||
当应用自己拥有业务流程时使用 UI 组件。当界面还需要导航、媒体存储、搜索适配器或通知查询等完整功能契约时,使用 `@workspace/blocks`。
|
当应用自己拥有业务流程时使用 UI 组件。导航和通知等完整应用外壳功能使用 `@workspace/blocks`,媒体与搜索等领域工作流使用 `@workspace/media` 或 `@workspace/search` 等专用包。
|
||||||
|
|||||||
Reference in New Issue
Block a user