@webx-ui/module-recipes 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +46 -0
- package/dist/RecipeCreateDialog.d.ts +4 -0
- package/dist/RecipeEditorPage.d.ts +18 -0
- package/dist/RecipeHistory.d.ts +2 -0
- package/dist/RecipesPage.d.ts +20 -0
- package/dist/api.d.ts +35 -0
- package/dist/editor.d.ts +19 -0
- package/dist/i18n.d.ts +2 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +1114 -0
- package/dist/index.js.map +1 -0
- package/dist/messages.d.ts +7 -0
- package/dist/minutes.d.ts +8 -0
- package/dist/module.d.ts +26 -0
- package/dist/style.css +1 -0
- package/dist/types.d.ts +95 -0
- package/package.json +65 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 webx-ui
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# @webx-ui/module-recipes
|
|
2
|
+
|
|
3
|
+
The front end of the recipes section of the [WebX UI](https://github.com/webx-ui/webx-ui) admin
|
|
4
|
+
panel: recipes — a gallery, ingredients, a method, nutrition, time and servings — the categories
|
|
5
|
+
they are filed under, and what they are rich in.
|
|
6
|
+
|
|
7
|
+
The other half is the Composer package `webx-ui/module-recipes`, which owns the recipes, their
|
|
8
|
+
pages and addresses, the `Recipe` markup, the Recipes block, `recipes()` for templates and the
|
|
9
|
+
API. A section appears in the panel when both halves are installed.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @webx-ui/module-recipes
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createAdmin } from '@webx-ui/module-admin'
|
|
19
|
+
import { recipes } from '@webx-ui/module-recipes'
|
|
20
|
+
import '@webx-ui/module-recipes/style.css'
|
|
21
|
+
|
|
22
|
+
createAdmin({
|
|
23
|
+
basePath: '/cms',
|
|
24
|
+
modules: [...recipes()],
|
|
25
|
+
}).mount()
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`recipes()` answers with three sections — the recipes, their categories and "Rich in" — because
|
|
29
|
+
the panel draws one entry per module. The server puts all three in the `recipes` group.
|
|
30
|
+
`recipes({ path: '/cookbook' })` puts them somewhere else inside the panel.
|
|
31
|
+
|
|
32
|
+
## What is here
|
|
33
|
+
|
|
34
|
+
- **The list** — every recipe at once, in the one order the site shows them. Recipes have no order
|
|
35
|
+
inside a category or a service, so the list can be dragged only while nothing narrows it; with a
|
|
36
|
+
filter on, the line under it says why the grips are gone.
|
|
37
|
+
- **The editor** — the described screen `recipes.form` with the tabs Recipe · Settings · SEO ·
|
|
38
|
+
History, autosaved into a draft and guarded by a revision. The categories, the nutrients, the
|
|
39
|
+
services and the similar recipes wait in the draft with the text and reach the site on
|
|
40
|
+
"Publish". A project adds its own fields with a patch into the `project-fields` card.
|
|
41
|
+
- **Categories and "Rich in"** — the panel's shared category screens (`categoryRoutes`), with
|
|
42
|
+
`recipeCategoriesOptions()` and `recipeNutrientsOptions()` exported for a panel that mounts them
|
|
43
|
+
elsewhere.
|
|
44
|
+
|
|
45
|
+
The words are English by default and come from the server in the panel's language
|
|
46
|
+
(`webx-recipes::`).
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {
|
|
2
|
+
field: HTMLDivElement;
|
|
3
|
+
}, any>;
|
|
4
|
+
export default _default;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor of one recipe: a head that stays put, the described screen under it, and the bar
|
|
3
|
+
* along the bottom where it is saved and published (§5.9).
|
|
4
|
+
*
|
|
5
|
+
* Everything between the head and the bar is `recipes.form` — the recipe, its settings, the SEO
|
|
6
|
+
* card `module-seo` patches on and the history — so a project adds its own field (an author's
|
|
7
|
+
* note) with a patch rather than a fork of this file. Saving is by autosave into the draft, and
|
|
8
|
+
* the draft carries the categories, the services and the similar recipes too: the site changes,
|
|
9
|
+
* all of it at once, only on "Publish". Edits are guarded by a revision: a save over somebody
|
|
10
|
+
* else's is refused with a 409 and the question of which version the site gets.
|
|
11
|
+
*/
|
|
12
|
+
type __VLS_Props = {
|
|
13
|
+
base?: string;
|
|
14
|
+
};
|
|
15
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
16
|
+
base: string;
|
|
17
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
18
|
+
export default _default;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every recipe at once, in the order the site shows them (§5.9).
|
|
3
|
+
*
|
|
4
|
+
* No paginator: this list is where recipes are put in order, and a drag cannot cross a page
|
|
5
|
+
* boundary. Recipes have one order and only one (decision 4) — no order inside a category, none
|
|
6
|
+
* inside a service — so the grips are there only while the list is the whole of it. Any filter
|
|
7
|
+
* makes it a selection with invisible gaps in it, the grips go away and the line under the list
|
|
8
|
+
* says why: that is the difference from services, where a category has an order of its own.
|
|
9
|
+
*
|
|
10
|
+
* A row is a card rather than a line of cells, which is what makes the same list work on a
|
|
11
|
+
* phone: the picture, the name and the address on one side, the categories and the state beside
|
|
12
|
+
* them on a wide screen and under them on a narrow one.
|
|
13
|
+
*/
|
|
14
|
+
type __VLS_Props = {
|
|
15
|
+
base?: string;
|
|
16
|
+
};
|
|
17
|
+
declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
18
|
+
base: string;
|
|
19
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
20
|
+
export default _default;
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { AdminContext } from '@webx-ui/module-admin';
|
|
2
|
+
import { RecipeDetail, RecipeInput, RecipeQuery, RecipeRow, RecipeSave, RecipesList, RecipeVersion } from './types';
|
|
3
|
+
export interface RecipesApi {
|
|
4
|
+
/** Every recipe, with what the list can be narrowed by. */
|
|
5
|
+
list(query?: RecipeQuery): Promise<RecipesList>;
|
|
6
|
+
/** One recipe as its editor opens it: the record, the screen's values and the revision. */
|
|
7
|
+
get(id: number): Promise<RecipeDetail>;
|
|
8
|
+
/** A new recipe, made in one transaction: a refused address leaves no bare row behind. */
|
|
9
|
+
create(input: RecipeInput): Promise<Pick<RecipeDetail, 'recipe' | 'values'>>;
|
|
10
|
+
/**
|
|
11
|
+
* Save the draft. Refused with a 409 when the revision is stale — the body is a
|
|
12
|
+
* {@link RecipeConflict} with the recipe as it now is.
|
|
13
|
+
*/
|
|
14
|
+
save(id: number, input: RecipeSave): Promise<RecipeDetail>;
|
|
15
|
+
/** Throw away what is waiting and keep what the site is showing. */
|
|
16
|
+
discard(id: number): Promise<RecipeDetail>;
|
|
17
|
+
publish(id: number): Promise<RecipeRow>;
|
|
18
|
+
unpublish(id: number): Promise<RecipeRow>;
|
|
19
|
+
remove(id: number): Promise<void>;
|
|
20
|
+
restore(id: number): Promise<RecipeRow>;
|
|
21
|
+
/** The publications, newest first. */
|
|
22
|
+
versions(id: number): Promise<RecipeVersion[]>;
|
|
23
|
+
/** An old publication becomes the draft; putting it on the site is a separate step. */
|
|
24
|
+
restoreVersion(id: number, number: number): Promise<RecipeDetail>;
|
|
25
|
+
/** The one order recipes have — never a category's (decision 4). */
|
|
26
|
+
reorder(ids: number[]): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
/** The path of the list under the panel's API. */
|
|
29
|
+
export declare const RECIPES_API = "recipes";
|
|
30
|
+
/**
|
|
31
|
+
* Everything under `/recipes`, below the panel's API path — except the categories and the
|
|
32
|
+
* nutrients, which are the panel's shared category API under `recipes/categories` and
|
|
33
|
+
* `recipes/nutrients`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createRecipesApi(admin: AdminContext): RecipesApi;
|
package/dist/editor.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { InjectionKey, Ref } from 'vue';
|
|
2
|
+
import { RecipeRow } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* What the editor knows and the nodes of `recipes.form` do not: the recipe being edited, and a
|
|
5
|
+
* way to read it again. The history needs both — its list is keyed by the recipe, and a restored
|
|
6
|
+
* version has to reach the fields the form is bound to.
|
|
7
|
+
*/
|
|
8
|
+
export interface RecipeEditorContext {
|
|
9
|
+
/** The recipe as the server last answered it, or `null` while the first request is out. */
|
|
10
|
+
recipe: Ref<RecipeRow | null>;
|
|
11
|
+
/** Whether this administrator may write at all. */
|
|
12
|
+
canManage: boolean;
|
|
13
|
+
/** Ask the server for the recipe again — after a restore, a publication, a discard. */
|
|
14
|
+
reload(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare const recipeEditorKey: InjectionKey<RecipeEditorContext>;
|
|
17
|
+
export declare function provideRecipeEditor(editor: RecipeEditorContext): void;
|
|
18
|
+
/** The editor above this node, or `null` outside one — a demo or a test draws nothing. */
|
|
19
|
+
export declare function useRecipeEditor(): RecipeEditorContext | null;
|
package/dist/i18n.d.ts
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { recipes, recipeCategoriesOptions, recipeNutrientsOptions, type RecipesOptions, } from './module';
|
|
2
|
+
export { createRecipesApi, RECIPES_API, type RecipesApi } from './api';
|
|
3
|
+
export { recipesMessages } from './messages';
|
|
4
|
+
export { formatMinutes } from './minutes';
|
|
5
|
+
export { provideRecipeEditor, recipeEditorKey, useRecipeEditor, type RecipeEditorContext, } from './editor';
|
|
6
|
+
export { default as WxRecipesPage } from './RecipesPage';
|
|
7
|
+
export { default as WxRecipeCreateDialog } from './RecipeCreateDialog';
|
|
8
|
+
export { default as WxRecipeEditorPage } from './RecipeEditorPage';
|
|
9
|
+
export { default as WxRecipeHistory } from './RecipeHistory';
|
|
10
|
+
export type { RecipeConflict, RecipeDetail, RecipeInput, RecipeQuery, RecipeRow, RecipeSave, RecipesList, RecipeStatus, RecipeTermRef, RecipeVersion, } from './types';
|