@lblod/ember-rdfa-editor-lblod-plugins 27.1.0 → 28.0.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/addon/components/common/documents/preview-list.gts +35 -0
  3. package/addon/components/{snippet-plugin/snippets/snippet-preview.gts → common/documents/preview.gts} +38 -22
  4. package/addon/components/common/documents/types.ts +19 -0
  5. package/addon/components/common/search/alert-load-error.gts +17 -6
  6. package/addon/components/common/search/alert-no-items.gts +15 -6
  7. package/addon/components/common/search/loading.gts +13 -0
  8. package/addon/components/common/vote-star-unfilled-icon.gts +25 -0
  9. package/addon/components/snippet-plugin/nodes/snippet.gts +4 -3
  10. package/addon/components/snippet-plugin/search-modal.gts +216 -0
  11. package/addon/components/snippet-plugin/snippet-insert.gts +7 -4
  12. package/addon/components/table-of-contents-plugin/ember-nodes/outline.hbs +1 -1
  13. package/addon/components/table-of-contents-plugin/ember-nodes/table-of-contents.hbs +4 -1
  14. package/addon/components/table-of-contents-plugin/ember-nodes/table-of-contents.ts +9 -4
  15. package/addon/helpers/pagination.ts +15 -3
  16. package/addon/plugins/structure-plugin/node.ts +44 -3
  17. package/addon/plugins/table-of-contents-plugin/index.ts +4 -1
  18. package/addon/plugins/table-of-contents-plugin/nodes/table-of-contents.ts +4 -4
  19. package/addon/plugins/table-of-contents-plugin/utils/index.ts +47 -4
  20. package/app/components/{snippet-plugin/snippets/snippet-list.js → common/documents/preview-list.js} +1 -1
  21. package/app/components/{snippet-plugin/snippets/snippet-preview.js → common/documents/preview.js} +1 -1
  22. package/declarations/addon/components/common/documents/preview-list.d.ts +14 -0
  23. package/declarations/addon/components/common/documents/preview.d.ts +21 -0
  24. package/declarations/addon/components/common/documents/types.d.ts +11 -0
  25. package/declarations/addon/components/common/search/alert-load-error.d.ts +11 -2
  26. package/declarations/addon/components/common/search/alert-no-items.d.ts +10 -2
  27. package/declarations/addon/components/common/search/loading.d.ts +5 -1
  28. package/declarations/addon/components/common/vote-star-unfilled-icon.d.ts +9 -0
  29. package/declarations/addon/components/snippet-plugin/nodes/snippet.d.ts +2 -1
  30. package/declarations/addon/components/snippet-plugin/search-modal.d.ts +4 -4
  31. package/declarations/addon/components/snippet-plugin/snippet-insert.d.ts +2 -2
  32. package/declarations/addon/components/table-of-contents-plugin/ember-nodes/table-of-contents.d.ts +1 -1
  33. package/declarations/addon/helpers/pagination.d.ts +4 -3
  34. package/declarations/addon/plugins/table-of-contents-plugin/index.d.ts +4 -1
  35. package/declarations/addon/plugins/table-of-contents-plugin/nodes/table-of-contents.d.ts +3 -3
  36. package/declarations/addon/plugins/table-of-contents-plugin/utils/index.d.ts +5 -7
  37. package/package.json +5 -5
  38. package/pnpm-lock.yaml +48 -56
  39. package/addon/components/common/search/loading.hbs +0 -3
  40. package/addon/components/snippet-plugin/search-modal.hbs +0 -85
  41. package/addon/components/snippet-plugin/search-modal.ts +0 -107
  42. package/addon/components/snippet-plugin/snippets/snippet-list.hbs +0 -12
  43. package/declarations/addon/components/snippet-plugin/snippets/snippet-list.d.ts +0 -1
  44. package/declarations/addon/components/snippet-plugin/snippets/snippet-preview.d.ts +0 -19
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @lblod/ember-rdfa-editor-lblod-plugins
2
2
 
3
+ ## 28.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#547](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/547) [`8dc7f0f`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/8dc7f0f3f57755ae2807e38c7f75a6b6fbff6248) Thanks [@abeforgit](https://github.com/abeforgit)! - Bump peerdeps to be compatible with editor v11
8
+
9
+ ### Minor Changes
10
+
11
+ - [#547](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/547) [`648e04b`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/648e04b4c4d59d717f9e9c2f24a57c22f45c222d) Thanks [@abeforgit](https://github.com/abeforgit)! - Make ToC compatible with new structure nodes
12
+
13
+ - [#548](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/548) [`9b90845`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/9b90845c524d8255dda98b872876b8fbd1728026) Thanks [@piemonkey](https://github.com/piemonkey)! - Convert snippet preview list into a generic component for displaying a list of documents
14
+
15
+ ### Patch Changes
16
+
17
+ - [#548](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/pull/548) [`704b9b7`](https://github.com/lblod/ember-rdfa-editor-lblod-plugins/commit/704b9b776ed61e374852c0cdf51fb7330dac557b) Thanks [@piemonkey](https://github.com/piemonkey)! - Add ability to mark favourites in a preview list
18
+
3
19
  ## 27.1.0
4
20
 
5
21
  ### Minor Changes
@@ -0,0 +1,35 @@
1
+ import Component from '@glimmer/component';
2
+ import AuList from '@appuniversum/ember-appuniversum/components/au-list';
3
+ import Preview from './preview';
4
+ import { PreviewableDocument } from './types';
5
+
6
+ interface Sig<Doc extends PreviewableDocument> {
7
+ Args: {
8
+ docs: Doc[];
9
+ onInsert: (toInsert: Doc) => void;
10
+ isFavourite?: (doc: Doc) => boolean;
11
+ toggleFavourite?: (doc: Doc) => void;
12
+ };
13
+ Element: HTMLDivElement;
14
+ }
15
+
16
+ export default class PreviewList<
17
+ Doc extends PreviewableDocument,
18
+ > extends Component<Sig<Doc>> {
19
+ <template>
20
+ {{#if @docs.length}}
21
+ <AuList as |Item|>
22
+ {{#each @docs as |doc|}}
23
+ <Item>
24
+ <Preview
25
+ @doc={{doc}}
26
+ @onInsert={{@onInsert}}
27
+ @isFavourite={{@isFavourite}}
28
+ @toggleFavourite={{@toggleFavourite}}
29
+ />
30
+ </Item>
31
+ {{/each}}
32
+ </AuList>
33
+ {{/if}}
34
+ </template>
35
+ }
@@ -2,41 +2,35 @@ import AuButton from '@appuniversum/ember-appuniversum/components/au-button';
2
2
  import AuIcon from '@appuniversum/ember-appuniversum/components/au-icon';
3
3
  import { NavDownIcon } from '@appuniversum/ember-appuniversum/components/icons/nav-down';
4
4
  import { NavUpIcon } from '@appuniversum/ember-appuniversum/components/icons/nav-up';
5
+ import { VoteStarFilledIcon } from '@appuniversum/ember-appuniversum/components/icons/vote-star-filled';
5
6
  import { on } from '@ember/modifier';
6
7
  import { action } from '@ember/object';
7
8
  import Component from '@glimmer/component';
8
9
  import { tracked } from '@glimmer/tracking';
9
-
10
- import { SayController } from '@lblod/ember-rdfa-editor';
11
- import {
12
- Snippet,
13
- SnippetPluginConfig,
14
- } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin';
15
10
  import t from 'ember-intl/helpers/t';
11
+ import { SayController } from '@lblod/ember-rdfa-editor';
12
+ import { PreviewableDocument } from './types';
13
+ import { VoteStarUnfilledIcon } from '../vote-star-unfilled-icon';
16
14
 
17
- interface Signature {
15
+ interface Signature<Doc extends PreviewableDocument> {
18
16
  Args: {
19
- config: SnippetPluginConfig;
20
- snippet: Snippet;
21
- onInsert: (content: string, title: string) => void;
17
+ doc: Doc;
18
+ onInsert: (toInsert: Doc) => void;
19
+ isFavourite?: (doc: Doc) => boolean;
20
+ toggleFavourite?: (doc: Doc) => void;
22
21
  };
23
22
  Element: HTMLDivElement;
24
23
  }
25
24
 
26
- export default class SnippetPreviewComponent extends Component<Signature> {
25
+ export default class DocumentPreview<
26
+ Doc extends PreviewableDocument,
27
+ > extends Component<Signature<Doc>> {
27
28
  @tracked controller?: SayController;
28
29
  @tracked isExpanded = false;
29
30
 
30
- get snippet(): Snippet {
31
- return this.args.snippet;
32
- }
33
-
34
31
  @action
35
32
  onInsert() {
36
- this.args.onInsert(
37
- this.args.snippet.content?.toHTML() ?? '',
38
- this.args.snippet.title ?? '',
39
- );
33
+ this.args.onInsert(this.args.doc);
40
34
  }
41
35
 
42
36
  @action
@@ -44,6 +38,14 @@ export default class SnippetPreviewComponent extends Component<Signature> {
44
38
  this.isExpanded = !this.isExpanded;
45
39
  }
46
40
 
41
+ get isFavourite() {
42
+ return this.args.isFavourite?.(this.args.doc);
43
+ }
44
+ toggleFavourite = (event: MouseEvent) => {
45
+ event.stopPropagation();
46
+ this.args.toggleFavourite?.(this.args.doc);
47
+ };
48
+
47
49
  <template>
48
50
  <div
49
51
  class='snippet-preview {{if this.isExpanded "snippet-preview--expanded"}}'
@@ -63,9 +65,23 @@ export default class SnippetPreviewComponent extends Component<Signature> {
63
65
  <AuIcon @icon={{NavDownIcon}} @size='large' />
64
66
  {{/if}}
65
67
  </AuButton>
68
+ {{#if @isFavourite}}
69
+ {{#if this.isFavourite}}
70
+ <AuButton
71
+ @skin='naked'
72
+ @icon={{VoteStarFilledIcon}}
73
+ {{on 'click' this.toggleFavourite}}
74
+ />
75
+ {{else}}
76
+ {{! This is weird but needed to get around the stroke-width styling of svgs in au-icons }}
77
+ <AuButton @skin='naked' {{on 'click' this.toggleFavourite}}>
78
+ <VoteStarUnfilledIcon />
79
+ </AuButton>
80
+ {{/if}}
81
+ {{/if}}
66
82
  {{! template-lint-disable no-heading-inside-button}}
67
83
  <h3 class='snippet-preview__title'>
68
- {{@snippet.title}}
84
+ {{@doc.title}}
69
85
  </h3>
70
86
  </div>
71
87
  <div
@@ -84,8 +100,8 @@ export default class SnippetPreviewComponent extends Component<Signature> {
84
100
  <div
85
101
  class='say-editor say-content rdfa-annotations rdfa-annotations-highlight rdfa-annotations-hover snippet-preview__content'
86
102
  >
87
- {{#if @snippet.content}}
88
- {{@snippet.content}}
103
+ {{#if @doc.content}}
104
+ {{@doc.content}}
89
105
  {{else}}
90
106
  <p class='au-u-italic'>{{t 'snippet-plugin.modal.no-content'}}</p>
91
107
  {{/if}}
@@ -0,0 +1,19 @@
1
+ import { htmlSafe } from '@ember/template';
2
+
3
+ import { optionMapOr } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/option';
4
+ import { SafeString } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/types';
5
+
6
+ interface PreviewableDocumentArgs {
7
+ title: string | null;
8
+ content: string | null;
9
+ }
10
+
11
+ export class PreviewableDocument {
12
+ content: SafeString | null;
13
+ title: string | null;
14
+
15
+ constructor({ title, content }: PreviewableDocumentArgs) {
16
+ this.content = optionMapOr(null, htmlSafe, content);
17
+ this.title = title;
18
+ }
19
+ }
@@ -1,23 +1,32 @@
1
+ import { TemplateOnlyComponent } from '@ember/component/template-only';
1
2
  import t from 'ember-intl/helpers/t';
2
- import AuAlert from '@appuniversum/ember-appuniversum/components/au-alert';
3
+ import AuAlert, {
4
+ AuAlertSignature,
5
+ } from '@appuniversum/ember-appuniversum/components/au-alert';
3
6
  import AuLinkExternal from '@appuniversum/ember-appuniversum/components/au-link-external';
4
7
  import { AlertTriangleIcon } from '@appuniversum/ember-appuniversum/components/icons/alert-triangle';
5
8
  import { MailIcon } from '@appuniversum/ember-appuniversum/components/icons/mail';
6
9
 
7
- <template>
10
+ interface Sig {
11
+ Args: {
12
+ error: unknown;
13
+ fullSize?: boolean;
14
+ };
15
+ Element: AuAlertSignature['Element'];
16
+ }
17
+
18
+ const AlertLoadError: TemplateOnlyComponent<Sig> = <template>
8
19
  <AuAlert
9
20
  @title={{t 'common.search.error-title'}}
10
21
  @skin='error'
11
22
  @icon={{AlertTriangleIcon}}
12
23
  @closable={{false}}
13
- {{! @glint-expect-error: not typesafe yet }}
14
24
  @size={{if @fullSize undefined 'small'}}
15
25
  class='au-u-margin'
16
- {{! @glint-expect-error: not typesafe yet }}
17
26
  ...attributes
18
27
  >
19
28
  <p>{{t 'common.search.error-intro'}}</p>
20
- {{! @glint-expect-error: not typesafe yet }}
29
+ {{! @glint-expect-error: This seems to work... I guess Error has a toString that is called? }}
21
30
  <code class='au-u-error error-code'>{{@error}}</code>
22
31
  <p>
23
32
  {{t 'common.search.error-outro'}}
@@ -31,4 +40,6 @@ import { MailIcon } from '@appuniversum/ember-appuniversum/components/icons/mail
31
40
  </AuLinkExternal>.
32
41
  </p>
33
42
  </AuAlert>
34
- </template>
43
+ </template>;
44
+
45
+ export default AlertLoadError;
@@ -1,18 +1,27 @@
1
+ import { TemplateOnlyComponent } from '@ember/component/template-only';
1
2
  import t from 'ember-intl/helpers/t';
2
- import AuAlert from '@appuniversum/ember-appuniversum/components/au-alert';
3
+ import AuAlert, {
4
+ AuAlertSignature,
5
+ } from '@appuniversum/ember-appuniversum/components/au-alert';
3
6
  import { CrossIcon } from '@appuniversum/ember-appuniversum/components/icons/cross';
4
7
 
5
- <template>
8
+ interface Sig {
9
+ Args: {
10
+ fullSize?: boolean;
11
+ };
12
+ Element: AuAlertSignature['Element'];
13
+ }
14
+
15
+ const AlertNoItems: TemplateOnlyComponent<Sig> = <template>
6
16
  <AuAlert
7
17
  @title={{t 'common.search.no-results'}}
8
18
  @skin='warning'
9
19
  @icon={{CrossIcon}}
10
- {{! @glint-expect-error: not typesafe yet }}
11
20
  @size={{if @fullSize undefined 'small'}}
12
21
  @closable={{false}}
13
- {{! @glint-expect-error: not typesafe yet }}
14
22
  class={{unless @fullSize 'au-u-margin-small'}}
15
- {{! @glint-expect-error: not typesafe yet }}
16
23
  ...attributes
17
24
  />
18
- </template>
25
+ </template>;
26
+
27
+ export default AlertNoItems;
@@ -0,0 +1,13 @@
1
+ import { TemplateOnlyComponent } from '@ember/component/template-only';
2
+ import t from 'ember-intl/helpers/t';
3
+ import AuLoader from '@appuniversum/ember-appuniversum/components/au-loader';
4
+
5
+ interface Sig {}
6
+
7
+ const SearchLoading: TemplateOnlyComponent<Sig> = <template>
8
+ <AuLoader @hideMessage={{true}}>
9
+ {{t 'common.search.loading'}}
10
+ </AuLoader>
11
+ </template>;
12
+
13
+ export default SearchLoading;
@@ -0,0 +1,25 @@
1
+ import type { TOC } from '@ember/component/template-only';
2
+
3
+ export interface VoteStarUnfilledIconSignature {
4
+ Element: SVGSVGElement;
5
+ }
6
+
7
+ /**
8
+ * There is no unfilled version in AU. Unfortunately, due to AU including a `stroke-width: 0` style
9
+ * for icons, this icon shouldn't be used inside an `AuIcon`, it should be used in place of one.
10
+ */
11
+ export const VoteStarUnfilledIcon: TOC<VoteStarUnfilledIconSignature> =
12
+ <template>
13
+ <svg
14
+ xmlns='http://www.w3.org/2000/svg'
15
+ viewBox='0 0 16 17'
16
+ class='au-c-icon'
17
+ {{! template-lint-disable no-inline-styles }}
18
+ style='stroke-width:10%;'
19
+ ...attributes
20
+ ><path
21
+ {{! template-lint-disable no-inline-styles }}
22
+ style='fill:none;'
23
+ d='M12 15.167a.668.668 0 0 1-.37-.112L8 12.635l-3.63 2.42a.667.667 0 0 1-1.01-.737l1.225-4.29-3.056-3.056A.668.668 0 0 1 2 5.834h3.588l1.816-3.631c.226-.452.967-.452 1.193 0l1.816 3.631H14a.667.667 0 0 1 .471 1.138l-3.056 3.056 1.226 4.29a.667.667 0 0 1-.641.85Z'
24
+ /></svg>
25
+ </template>;
@@ -33,6 +33,7 @@ import { createSnippetPlaceholder } from '@lblod/ember-rdfa-editor-lblod-plugins
33
33
  import { hasDecendant } from '@lblod/ember-rdfa-editor-lblod-plugins/utils/has-descendant';
34
34
  import SnippetPlaceholder from '@lblod/ember-rdfa-editor-lblod-plugins/components/snippet-plugin/nodes/placeholder';
35
35
  import { getSnippetListUrisFromNode } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin/utils/rdfa-predicate';
36
+ import { Snippet } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin';
36
37
 
37
38
  interface ButtonSig {
38
39
  Args: {
@@ -177,7 +178,7 @@ export default class SnippetNode extends Component<Signature> {
177
178
  return ancestor && ancestor.node === this.node;
178
179
  }
179
180
  @action
180
- onInsert(content: string, title: string) {
181
+ onInsert(snippet: Snippet) {
181
182
  this.closeModal();
182
183
  let start = 0;
183
184
  let end = 0;
@@ -196,8 +197,8 @@ export default class SnippetNode extends Component<Signature> {
196
197
  }
197
198
  this.controller.doCommand(
198
199
  insertSnippet({
199
- content,
200
- title,
200
+ content: snippet.content?.toHTML() ?? '',
201
+ title: snippet.title ?? '',
201
202
  listProperties: {
202
203
  placeholderId: this.node.attrs.placeholderId,
203
204
  listUris: getSnippetListUrisFromNode(this.node),
@@ -0,0 +1,216 @@
1
+ import pagination from '@lblod/ember-rdfa-editor-lblod-plugins/helpers/pagination';
2
+ import Component from '@glimmer/component';
3
+ import { assert } from '@ember/debug';
4
+ import { action } from '@ember/object';
5
+ import { restartableTask, timeout } from 'ember-concurrency';
6
+ import { task as trackedTask } from 'reactiveweb/ember-concurrency';
7
+ import { tracked } from '@glimmer/tracking';
8
+ import { on } from '@ember/modifier';
9
+ import t from 'ember-intl/helpers/t';
10
+ import { not } from 'ember-truth-helpers';
11
+ import AuModal from '@appuniversum/ember-appuniversum/components/au-modal';
12
+ import AuMainContainer from '@appuniversum/ember-appuniversum/components/au-main-container';
13
+ import AuHeading from '@appuniversum/ember-appuniversum/components/au-heading';
14
+ import AuLabel from '@appuniversum/ember-appuniversum/components/au-label';
15
+
16
+ import AuNativeInput from '@lblod/ember-rdfa-editor-lblod-plugins/components/au-native-input';
17
+ import Loading from '@lblod/ember-rdfa-editor-lblod-plugins/components/common/search/loading';
18
+ import AlertLoadError from '@lblod/ember-rdfa-editor-lblod-plugins/components/common/search/alert-load-error';
19
+ import { fetchSnippets } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin/utils/fetch-data';
20
+ import {
21
+ Snippet,
22
+ SnippetPluginConfig,
23
+ } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin';
24
+ import PreviewList from '@lblod/ember-rdfa-editor-lblod-plugins/components/common/documents/preview-list';
25
+ import AlertNoItems from '@lblod/ember-rdfa-editor-lblod-plugins/components/common/search/alert-no-items';
26
+ import PaginationView from '@lblod/ember-rdfa-editor-lblod-plugins/components/pagination/pagination-view';
27
+
28
+ interface Args {
29
+ config: SnippetPluginConfig;
30
+ snippetListUris: string[] | undefined;
31
+ snippetListNames: string[] | undefined;
32
+ closeModal: () => void;
33
+ open: boolean;
34
+ onInsert: (snippet: Snippet) => void;
35
+ }
36
+
37
+ export default class SnippetPluginSearchModalComponent extends Component<Args> {
38
+ // Filtering
39
+ @tracked inputSearchText: string | null = null;
40
+
41
+ // Display
42
+ @tracked error: unknown;
43
+
44
+ // Pagination
45
+ @tracked pageNumber = 0;
46
+ @tracked pageSize = 20;
47
+ @tracked totalCount = 0;
48
+
49
+ get config() {
50
+ return this.args.config;
51
+ }
52
+
53
+ get searchText() {
54
+ return this.inputSearchText;
55
+ }
56
+
57
+ get snippetListNames() {
58
+ return this.args.snippetListNames?.map((name) => `"${name}"`).join(', ');
59
+ }
60
+
61
+ @action
62
+ setInputSearchText(event: InputEvent) {
63
+ assert(
64
+ 'inputSearchText must be bound to an input element',
65
+ event.target instanceof HTMLInputElement,
66
+ );
67
+
68
+ this.inputSearchText = event.target.value;
69
+ }
70
+
71
+ @action
72
+ async closeModal() {
73
+ await this.snippetsResource.cancel();
74
+ this.args.closeModal();
75
+ }
76
+
77
+ snippetsSearch = restartableTask(async () => {
78
+ await timeout(500);
79
+
80
+ const abortController = new AbortController();
81
+
82
+ try {
83
+ const queryResult = await fetchSnippets({
84
+ endpoint: this.args.config.endpoint,
85
+ abortSignal: abortController.signal,
86
+ filter: {
87
+ name: this.inputSearchText ?? undefined,
88
+ snippetListUris: this.args.snippetListUris ?? undefined,
89
+ },
90
+ pagination: {
91
+ pageNumber: this.pageNumber,
92
+ pageSize: this.pageSize,
93
+ },
94
+ });
95
+
96
+ this.totalCount = queryResult.totalCount;
97
+
98
+ return queryResult.results;
99
+ } catch (error) {
100
+ this.error = error;
101
+ return [];
102
+ } finally {
103
+ abortController.abort();
104
+ }
105
+ });
106
+
107
+ snippetsResource = trackedTask<Snippet[]>(this, this.snippetsSearch, () => [
108
+ this.inputSearchText,
109
+ this.pageNumber,
110
+ this.pageSize,
111
+ this.args.snippetListUris,
112
+ ]);
113
+
114
+ @action
115
+ previousPage() {
116
+ --this.pageNumber;
117
+ }
118
+
119
+ @action
120
+ nextPage() {
121
+ ++this.pageNumber;
122
+ }
123
+
124
+ <template>
125
+ <AuModal
126
+ class='snippet-modal'
127
+ @modalOpen={{@open}}
128
+ @closeModal={{this.closeModal}}
129
+ @title={{t
130
+ 'snippet-plugin.modal.title'
131
+ snippetListNames=this.snippetListNames
132
+ }}
133
+ @size='large'
134
+ @padding='none'
135
+ as |modal|
136
+ >
137
+ <modal.Body>
138
+ <AuMainContainer class='snippet-modal--main-container' as |mc|>
139
+ <mc.sidebar>
140
+ <div class='au-c-sidebar'>
141
+ <div class='au-c-sidebar__content au-u-padding'>
142
+ <AuHeading
143
+ @level='3'
144
+ @skin='4'
145
+ class='au-u-padding-bottom-small'
146
+ >
147
+ {{t 'snippet-plugin.modal.search.title'}}
148
+ </AuHeading>
149
+ <AuLabel
150
+ class='au-margin-bottom-small'
151
+ for='searchTerm'
152
+ @inline={{false}}
153
+ @required={{false}}
154
+ @error={{false}}
155
+ @warning={{false}}
156
+ >
157
+ {{t 'snippet-plugin.modal.search.label'}}
158
+ </AuLabel>
159
+ <AuNativeInput
160
+ @type='text'
161
+ @width='block'
162
+ id='searchTerm'
163
+ value={{this.searchText}}
164
+ placeholder={{t 'snippet-plugin.modal.search.placeholder'}}
165
+ {{on 'input' this.setInputSearchText}}
166
+ />
167
+ </div>
168
+ </div>
169
+ </mc.sidebar>
170
+ <mc.content @scroll={{true}}>
171
+ <div class='au-u-padding-top snippet-modal--list-container'>
172
+ {{#if this.snippetsResource.isRunning}}
173
+ <div class='au-u-margin'>
174
+ <Loading />
175
+ </div>
176
+ {{else}}
177
+ {{#if this.error}}
178
+ <AlertLoadError @error={{this.error}} />
179
+ {{else}}
180
+ {{#if this.snippetsResource.value.length}}
181
+ <PreviewList
182
+ @docs={{this.snippetsResource.value}}
183
+ @onInsert={{@onInsert}}
184
+ />
185
+ {{else}}
186
+ <AlertNoItems />
187
+ {{/if}}
188
+ {{/if}}
189
+ {{/if}}
190
+ </div>
191
+ {{#if this.snippetsResource.value.length}}
192
+ {{#let
193
+ (pagination
194
+ page=this.pageNumber
195
+ pageSize=this.pageSize
196
+ count=this.totalCount
197
+ )
198
+ as |pg|
199
+ }}
200
+ <PaginationView
201
+ @totalCount={{pg.count}}
202
+ @rangeStart={{pg.pageStart}}
203
+ @rangeEnd={{pg.pageEnd}}
204
+ @onNextPage={{this.nextPage}}
205
+ @onPreviousPage={{this.previousPage}}
206
+ @isFirstPage={{not pg.hasPreviousPage}}
207
+ @isLastPage={{not pg.hasNextPage}}
208
+ />
209
+ {{/let}}
210
+ {{/if}}
211
+ </mc.content>
212
+ </AuMainContainer>
213
+ </modal.Body>
214
+ </AuModal>
215
+ </template>
216
+ }
@@ -10,7 +10,10 @@ import {
10
10
  type SayController,
11
11
  Slice,
12
12
  } from '@lblod/ember-rdfa-editor';
13
- import { SnippetPluginConfig } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin';
13
+ import {
14
+ Snippet,
15
+ SnippetPluginConfig,
16
+ } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin';
14
17
  import { type SnippetListProperties } from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin';
15
18
  import insertSnippet from '@lblod/ember-rdfa-editor-lblod-plugins/plugins/snippet-plugin/commands/insert-snippet';
16
19
  import SearchModal from './search-modal';
@@ -56,13 +59,13 @@ export default class SnippetInsertComponent extends Component<Sig> {
56
59
  }
57
60
 
58
61
  @action
59
- onInsert(content: string, title: string) {
62
+ onInsert(snippet: Snippet) {
60
63
  this.closeModal();
61
64
  if (this.args.listProperties) {
62
65
  this.controller.doCommand(
63
66
  insertSnippet({
64
- content,
65
- title,
67
+ content: snippet.content?.toHTML() ?? '',
68
+ title: snippet.title ?? '',
66
69
  listProperties: this.args.listProperties,
67
70
  allowMultipleSnippets: this.args.allowMultipleSnippets,
68
71
  }),
@@ -6,7 +6,7 @@
6
6
  {{! template-lint-disable no-capital-arguments }}
7
7
  @block={{true}}
8
8
  @skin='link-secondary'
9
- onclick={{fn @onEntryClick outlineEntry.pos}}
9
+ {{on 'click' (fn @onEntryClick outlineEntry.pos)}}
10
10
  >
11
11
  {{outlineEntry.content}}
12
12
  </AuButton>
@@ -1,5 +1,8 @@
1
1
  {{! @glint-nocheck: not typesafe yet }}
2
- <div class='au-u-background-gray-100 au-u-padding-tiny table-of-contents'>
2
+ <div
3
+ class='au-u-background-gray-100 au-u-padding-tiny table-of-contents'
4
+ contenteditable='false'
5
+ >
3
6
  <h3>{{this.title}}</h3>
4
7
  {{#if this.outline}}
5
8
  <TableOfContentsPlugin::EmberNodes::Outline
@@ -8,8 +8,8 @@ import { service } from '@ember/service';
8
8
  import IntlService from 'ember-intl/services/intl';
9
9
  export default class TableOfContentsComponent extends Component<EmberNodeArgs> {
10
10
  @service declare intl: IntlService;
11
- get config() {
12
- return this.args.node.attrs['config'] as TableOfContentsConfig;
11
+ get config(): TableOfContentsConfig | undefined {
12
+ return this.args.node.attrs['config'] as TableOfContentsConfig | undefined;
13
13
  }
14
14
 
15
15
  get documentLanguage() {
@@ -49,9 +49,14 @@ export default class TableOfContentsComponent extends Component<EmberNodeArgs> {
49
49
  const coords = this.controller.mainEditorView.coordsAtPos(
50
50
  selection.from,
51
51
  );
52
- const config = this.config[0];
52
+ let config;
53
+ if (Array.isArray(this.config)) {
54
+ config = this.config[0];
55
+ } else {
56
+ config = this.config;
57
+ }
53
58
  let scrollContainer: HTMLElement | undefined;
54
- if (config.scrollContainer) {
59
+ if (config?.scrollContainer) {
55
60
  scrollContainer = config.scrollContainer();
56
61
  } else {
57
62
  scrollContainer = this.getScrollContainer();
@@ -7,12 +7,24 @@ interface PaginationArguments {
7
7
  pageSize: number;
8
8
  page: number;
9
9
  }
10
+ interface PaginationResult {
11
+ count: number;
12
+ pageSize: number;
13
+ page: number;
14
+ totalPages: number;
15
+ pageStart: number;
16
+ pageEnd: number;
17
+ nextPage: number | null;
18
+ previousPage: number | null;
19
+ hasPreviousPage: boolean;
20
+ hasNextPage: boolean;
21
+ }
10
22
 
11
23
  export function pagination({
12
24
  page = 0,
13
25
  count = 0,
14
26
  pageSize = 20,
15
- }: PaginationArguments) {
27
+ }: PaginationArguments): PaginationResult {
16
28
  const totalPages = count / pageSize;
17
29
  const pageStart = page * pageSize + 1;
18
30
  const pageEnd = Math.min((page + 1) * pageSize, count);
@@ -35,6 +47,6 @@ export function pagination({
35
47
  };
36
48
  }
37
49
 
38
- export default helper<unknown[], PaginationArguments>((_, named) =>
39
- pagination(named),
50
+ export default helper<unknown[], PaginationArguments, PaginationResult>(
51
+ (_, named) => pagination(named),
40
52
  );