@eightyfourthousand/lib-editing 2026.3.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/.babelrc +12 -0
- package/.eslintrc.json +18 -0
- package/README.md +7 -0
- package/jest.config.ts +10 -0
- package/package.json +35 -0
- package/postcss.config.mjs +9 -0
- package/project.json +29 -0
- package/src/fixtures/basic/json.ts +396 -0
- package/src/fixtures/toh251/json.ts +4913 -0
- package/src/fixtures/toh251/passages.ts +2814 -0
- package/src/fixtures/types.ts +8 -0
- package/src/index.ts +4 -0
- package/src/lib/block.ts +226 -0
- package/src/lib/components/editor/BlockEditor.tsx +38 -0
- package/src/lib/components/editor/EditorBackMatterPage.tsx +95 -0
- package/src/lib/components/editor/EditorBodyPage.tsx +87 -0
- package/src/lib/components/editor/EditorHeader.tsx +22 -0
- package/src/lib/components/editor/EditorLayout.tsx +62 -0
- package/src/lib/components/editor/EditorLeftPanelPage.tsx +27 -0
- package/src/lib/components/editor/EditorProvider.tsx +399 -0
- package/src/lib/components/editor/PaginationProvider.tsx +472 -0
- package/src/lib/components/editor/TitlesBuilder.tsx +40 -0
- package/src/lib/components/editor/TranslationBuilder.tsx +171 -0
- package/src/lib/components/editor/TranslationEditor.tsx +32 -0
- package/src/lib/components/editor/extensions/Abbreviation/Abbreviation.ts +133 -0
- package/src/lib/components/editor/extensions/Audio/Audio.ts +69 -0
- package/src/lib/components/editor/extensions/Bold.ts +43 -0
- package/src/lib/components/editor/extensions/Document.ts +8 -0
- package/src/lib/components/editor/extensions/DragHandle/DragHandle.ts +429 -0
- package/src/lib/components/editor/extensions/EndNoteLink/EndNoteLink.tsx +39 -0
- package/src/lib/components/editor/extensions/EndNoteLink/EndNoteLinkHoverContent.tsx +139 -0
- package/src/lib/components/editor/extensions/EndNoteLink/EndNoteLinkMark.ts +236 -0
- package/src/lib/components/editor/extensions/EndNoteLink/endnote-utils.ts +412 -0
- package/src/lib/components/editor/extensions/GlobalConfig.ts +52 -0
- package/src/lib/components/editor/extensions/GlossaryInstance/GlossaryInput.tsx +54 -0
- package/src/lib/components/editor/extensions/GlossaryInstance/GlossaryInstance.tsx +129 -0
- package/src/lib/components/editor/extensions/GlossaryInstance/GlossaryInstanceNode.ts +148 -0
- package/src/lib/components/editor/extensions/Heading/Heading.ts +71 -0
- package/src/lib/components/editor/extensions/HoverInputField.tsx +54 -0
- package/src/lib/components/editor/extensions/Image.ts +18 -0
- package/src/lib/components/editor/extensions/Indent.ts +103 -0
- package/src/lib/components/editor/extensions/InternalLink/InternalLink.ts +173 -0
- package/src/lib/components/editor/extensions/InternalLink/InternalLinkHoverContent.tsx +137 -0
- package/src/lib/components/editor/extensions/InternalLink/InternalLinkInput.tsx +71 -0
- package/src/lib/components/editor/extensions/InternalLink/index.ts +1 -0
- package/src/lib/components/editor/extensions/Italic.ts +50 -0
- package/src/lib/components/editor/extensions/LeadingSpace.ts +106 -0
- package/src/lib/components/editor/extensions/Line/LineNode.ts +41 -0
- package/src/lib/components/editor/extensions/LineGroup/LineGroupNode.ts +124 -0
- package/src/lib/components/editor/extensions/Link/Link.ts +65 -0
- package/src/lib/components/editor/extensions/Link/LinkHoverContent.tsx +124 -0
- package/src/lib/components/editor/extensions/Link/index.ts +1 -0
- package/src/lib/components/editor/extensions/List.ts +74 -0
- package/src/lib/components/editor/extensions/Mantra/Mantra.ts +88 -0
- package/src/lib/components/editor/extensions/Mention/Mention.ts +184 -0
- package/src/lib/components/editor/extensions/Mention/MentionHoverContent.tsx +158 -0
- package/src/lib/components/editor/extensions/NodeWrapper.tsx +57 -0
- package/src/lib/components/editor/extensions/Paragraph/Paragraph.ts +25 -0
- package/src/lib/components/editor/extensions/ParagraphIndent.ts +87 -0
- package/src/lib/components/editor/extensions/Passage/EditLabel.tsx +57 -0
- package/src/lib/components/editor/extensions/Passage/EditorOptions.tsx +29 -0
- package/src/lib/components/editor/extensions/Passage/Passage.tsx +238 -0
- package/src/lib/components/editor/extensions/Passage/PassageNode.ts +223 -0
- package/src/lib/components/editor/extensions/Passage/ReaderOptions.tsx +55 -0
- package/src/lib/components/editor/extensions/Passage/ShowAnnotations.tsx +92 -0
- package/src/lib/components/editor/extensions/Passage/index.ts +1 -0
- package/src/lib/components/editor/extensions/Passage/label.spec.ts +118 -0
- package/src/lib/components/editor/extensions/Passage/label.ts +39 -0
- package/src/lib/components/editor/extensions/Placeholder.ts +9 -0
- package/src/lib/components/editor/extensions/SlashCommand/SlashCommand.ts +65 -0
- package/src/lib/components/editor/extensions/SlashCommand/SuggestionList.tsx +109 -0
- package/src/lib/components/editor/extensions/SlashCommand/Suggestions.ts +185 -0
- package/src/lib/components/editor/extensions/SmallCaps.ts +110 -0
- package/src/lib/components/editor/extensions/StarterKit.ts +36 -0
- package/src/lib/components/editor/extensions/Subscript.ts +43 -0
- package/src/lib/components/editor/extensions/Superscript.ts +43 -0
- package/src/lib/components/editor/extensions/Table.ts +32 -0
- package/src/lib/components/editor/extensions/TextAlign.ts +5 -0
- package/src/lib/components/editor/extensions/TitleMetadata.ts +40 -0
- package/src/lib/components/editor/extensions/TitleNode.ts +133 -0
- package/src/lib/components/editor/extensions/TitlesNode.ts +102 -0
- package/src/lib/components/editor/extensions/Trailer.ts +57 -0
- package/src/lib/components/editor/extensions/TranslationDocument.ts +7 -0
- package/src/lib/components/editor/extensions/TranslationMetadata.ts +58 -0
- package/src/lib/components/editor/extensions/Underline.ts +43 -0
- package/src/lib/components/editor/hooks/index.ts +4 -0
- package/src/lib/components/editor/hooks/useBlockEditor.ts +53 -0
- package/src/lib/components/editor/hooks/useDefaultExtensions.ts +39 -0
- package/src/lib/components/editor/hooks/useDirtyStore.ts +33 -0
- package/src/lib/components/editor/hooks/useTranslationExtensions.ts +148 -0
- package/src/lib/components/editor/index.ts +10 -0
- package/src/lib/components/editor/menus/EmptyBubbleMenu.tsx +42 -0
- package/src/lib/components/editor/menus/MainBubbleMenu.tsx +51 -0
- package/src/lib/components/editor/menus/TranslationBubbleMenu.tsx +57 -0
- package/src/lib/components/editor/menus/index.ts +3 -0
- package/src/lib/components/editor/menus/selectors/EndNoteSelector.tsx +388 -0
- package/src/lib/components/editor/menus/selectors/GlossarySelector.tsx +63 -0
- package/src/lib/components/editor/menus/selectors/LinkSelector.tsx +68 -0
- package/src/lib/components/editor/menus/selectors/MantraSelector.tsx +119 -0
- package/src/lib/components/editor/menus/selectors/NodeSelector.tsx +144 -0
- package/src/lib/components/editor/menus/selectors/ParagraphButtons.tsx +68 -0
- package/src/lib/components/editor/menus/selectors/SelectorInputField.tsx +68 -0
- package/src/lib/components/editor/menus/selectors/TextAlignSelector.tsx +89 -0
- package/src/lib/components/editor/menus/selectors/TextButtons.tsx +89 -0
- package/src/lib/components/editor/menus/selectors/TranslationNodeSelector.tsx +143 -0
- package/src/lib/components/editor/menus/selectors/TranslationTextButtons.tsx +125 -0
- package/src/lib/components/editor/menus/selectors/index.ts +5 -0
- package/src/lib/components/editor/save-filter.spec.ts +94 -0
- package/src/lib/components/editor/save-filter.ts +27 -0
- package/src/lib/components/editor/util.ts +304 -0
- package/src/lib/components/index.ts +3 -0
- package/src/lib/components/reader/ReaderBackMatterPage.tsx +62 -0
- package/src/lib/components/reader/ReaderBackMatterPanel.tsx +53 -0
- package/src/lib/components/reader/ReaderBodyPage.tsx +46 -0
- package/src/lib/components/reader/ReaderBodyPanel.tsx +68 -0
- package/src/lib/components/reader/ReaderLayout.tsx +39 -0
- package/src/lib/components/reader/ReaderLeftPanel.tsx +8 -0
- package/src/lib/components/reader/ReaderLeftPanelPage.tsx +31 -0
- package/src/lib/components/reader/TranslationReader.tsx +28 -0
- package/src/lib/components/reader/index.ts +2 -0
- package/src/lib/components/reader/ssr.ts +3 -0
- package/src/lib/components/shared/AiSummarizerPage.tsx +12 -0
- package/src/lib/components/shared/BackMatterPanel.tsx +143 -0
- package/src/lib/components/shared/BodyPanel.tsx +214 -0
- package/src/lib/components/shared/HoverCardProvider.tsx +407 -0
- package/src/lib/components/shared/Imprint.tsx +24 -0
- package/src/lib/components/shared/LabeledElement.tsx +133 -0
- package/src/lib/components/shared/LeftPanel.tsx +65 -0
- package/src/lib/components/shared/NavigationContext.ts +64 -0
- package/src/lib/components/shared/NavigationProvider.tsx +368 -0
- package/src/lib/components/shared/OpenGraphImage.tsx +75 -0
- package/src/lib/components/shared/PassageSkeleton.tsx +10 -0
- package/src/lib/components/shared/RestrictionWarning.tsx +177 -0
- package/src/lib/components/shared/SourceReader.tsx +83 -0
- package/src/lib/components/shared/SuggestRevisionForm.tsx +99 -0
- package/src/lib/components/shared/TableOfContents.tsx +280 -0
- package/src/lib/components/shared/ThreeColumnRenderer.tsx +54 -0
- package/src/lib/components/shared/TranslationHeader.tsx +86 -0
- package/src/lib/components/shared/TranslationHoverCard.tsx +84 -0
- package/src/lib/components/shared/TranslationSkeleton.tsx +16 -0
- package/src/lib/components/shared/TranslationTable.tsx +155 -0
- package/src/lib/components/shared/bibliography/BibliographyBody.tsx +28 -0
- package/src/lib/components/shared/bibliography/BibliographyList.tsx +63 -0
- package/src/lib/components/shared/bibliography/index.ts +1 -0
- package/src/lib/components/shared/generate-metadata.ts +44 -0
- package/src/lib/components/shared/glossary/GlossaryInstanceBody.tsx +144 -0
- package/src/lib/components/shared/glossary/GlossaryPaginationProvider.tsx +317 -0
- package/src/lib/components/shared/glossary/GlossarySkeleton.tsx +19 -0
- package/src/lib/components/shared/glossary/GlossaryTermList.tsx +58 -0
- package/src/lib/components/shared/glossary/index.ts +3 -0
- package/src/lib/components/shared/hooks/useGlossaryInstanceListener.tsx +42 -0
- package/src/lib/components/shared/hooks/useScrollInTab.tsx +43 -0
- package/src/lib/components/shared/hooks/useScrollPositionRestore.ts +274 -0
- package/src/lib/components/shared/hooks/useTohToggle.tsx +52 -0
- package/src/lib/components/shared/index.ts +11 -0
- package/src/lib/components/shared/ssr.ts +2 -0
- package/src/lib/components/shared/titles/FramedCard.tsx +132 -0
- package/src/lib/components/shared/titles/LongTitle.tsx +20 -0
- package/src/lib/components/shared/titles/LongTitles.tsx +28 -0
- package/src/lib/components/shared/titles/Title.tsx +54 -0
- package/src/lib/components/shared/titles/TitleDetails.tsx +47 -0
- package/src/lib/components/shared/titles/TitleForm.tsx +37 -0
- package/src/lib/components/shared/titles/Titles.tsx +114 -0
- package/src/lib/components/shared/titles/TitlesCard.tsx +113 -0
- package/src/lib/components/shared/titles/index.ts +8 -0
- package/src/lib/components/shared/types.ts +79 -0
- package/src/lib/components/ssr.ts +2 -0
- package/src/lib/exporters/abbreviation.spec.ts +31 -0
- package/src/lib/exporters/abbreviation.ts +22 -0
- package/src/lib/exporters/annotation.ts +193 -0
- package/src/lib/exporters/audio.spec.ts +77 -0
- package/src/lib/exporters/audio.ts +27 -0
- package/src/lib/exporters/blockquote.spec.ts +48 -0
- package/src/lib/exporters/blockquote.ts +24 -0
- package/src/lib/exporters/code.spec.ts +93 -0
- package/src/lib/exporters/code.ts +26 -0
- package/src/lib/exporters/end-note-link.spec.ts +104 -0
- package/src/lib/exporters/end-note-link.ts +35 -0
- package/src/lib/exporters/export.ts +12 -0
- package/src/lib/exporters/glossary-instance.spec.ts +85 -0
- package/src/lib/exporters/glossary-instance.ts +31 -0
- package/src/lib/exporters/has-abbreviation.spec.ts +31 -0
- package/src/lib/exporters/has-abbreviation.ts +21 -0
- package/src/lib/exporters/heading.spec.ts +80 -0
- package/src/lib/exporters/heading.ts +28 -0
- package/src/lib/exporters/image.spec.ts +48 -0
- package/src/lib/exporters/image.ts +25 -0
- package/src/lib/exporters/indent.spec.ts +58 -0
- package/src/lib/exporters/indent.ts +18 -0
- package/src/lib/exporters/index.ts +1 -0
- package/src/lib/exporters/internal-link.spec.ts +90 -0
- package/src/lib/exporters/internal-link.ts +35 -0
- package/src/lib/exporters/italic.spec.ts +84 -0
- package/src/lib/exporters/italic.ts +55 -0
- package/src/lib/exporters/leading-space.spec.ts +28 -0
- package/src/lib/exporters/leading-space.ts +16 -0
- package/src/lib/exporters/line-group.spec.ts +48 -0
- package/src/lib/exporters/line-group.ts +24 -0
- package/src/lib/exporters/line.spec.ts +48 -0
- package/src/lib/exporters/line.ts +24 -0
- package/src/lib/exporters/link.spec.ts +123 -0
- package/src/lib/exporters/link.ts +67 -0
- package/src/lib/exporters/list-item.spec.ts +48 -0
- package/src/lib/exporters/list-item.ts +24 -0
- package/src/lib/exporters/list.spec.ts +82 -0
- package/src/lib/exporters/list.ts +31 -0
- package/src/lib/exporters/mantra.spec.ts +51 -0
- package/src/lib/exporters/mantra.ts +25 -0
- package/src/lib/exporters/mention.ts +41 -0
- package/src/lib/exporters/paragraph.spec.ts +173 -0
- package/src/lib/exporters/paragraph.ts +32 -0
- package/src/lib/exporters/quote.spec.ts +56 -0
- package/src/lib/exporters/quote.ts +25 -0
- package/src/lib/exporters/span.spec.ts +118 -0
- package/src/lib/exporters/span.ts +44 -0
- package/src/lib/exporters/table-body-data.spec.ts +48 -0
- package/src/lib/exporters/table-body-data.ts +24 -0
- package/src/lib/exporters/table-body-header.spec.ts +48 -0
- package/src/lib/exporters/table-body-header.ts +24 -0
- package/src/lib/exporters/table-body-row.spec.ts +48 -0
- package/src/lib/exporters/table-body-row.ts +24 -0
- package/src/lib/exporters/table.spec.ts +48 -0
- package/src/lib/exporters/table.ts +24 -0
- package/src/lib/exporters/trailer.spec.ts +48 -0
- package/src/lib/exporters/trailer.ts +24 -0
- package/src/lib/exporters/util.ts +62 -0
- package/src/lib/passage.ts +182 -0
- package/src/lib/titles.ts +80 -0
- package/src/lib/transformers/abbreviation.spec.ts +87 -0
- package/src/lib/transformers/abbreviation.ts +30 -0
- package/src/lib/transformers/annotate.ts +146 -0
- package/src/lib/transformers/audio.spec.ts +55 -0
- package/src/lib/transformers/audio.ts +29 -0
- package/src/lib/transformers/blockquote.spec.ts +48 -0
- package/src/lib/transformers/blockquote.ts +41 -0
- package/src/lib/transformers/code.spec.ts +52 -0
- package/src/lib/transformers/code.ts +22 -0
- package/src/lib/transformers/deprecated.ts +7 -0
- package/src/lib/transformers/end-note-link.spec.ts +56 -0
- package/src/lib/transformers/end-note-link.ts +76 -0
- package/src/lib/transformers/glossary-instance.spec.ts +55 -0
- package/src/lib/transformers/glossary-instance.ts +40 -0
- package/src/lib/transformers/has-abbreviation.spec.ts +50 -0
- package/src/lib/transformers/has-abbreviation.ts +30 -0
- package/src/lib/transformers/heading.spec.ts +62 -0
- package/src/lib/transformers/heading.ts +30 -0
- package/src/lib/transformers/image.spec.ts +51 -0
- package/src/lib/transformers/image.ts +28 -0
- package/src/lib/transformers/indent.spec.ts +53 -0
- package/src/lib/transformers/indent.ts +17 -0
- package/src/lib/transformers/index.ts +33 -0
- package/src/lib/transformers/inline-title.spec.ts +59 -0
- package/src/lib/transformers/inline-title.ts +34 -0
- package/src/lib/transformers/internal-link.spec.ts +67 -0
- package/src/lib/transformers/internal-link.ts +65 -0
- package/src/lib/transformers/italic.ts +22 -0
- package/src/lib/transformers/leading-space.spec.ts +55 -0
- package/src/lib/transformers/leading-space.ts +17 -0
- package/src/lib/transformers/line-group.spec.ts +48 -0
- package/src/lib/transformers/line-group.ts +37 -0
- package/src/lib/transformers/line.spec.ts +54 -0
- package/src/lib/transformers/line.ts +27 -0
- package/src/lib/transformers/link.spec.ts +61 -0
- package/src/lib/transformers/link.ts +27 -0
- package/src/lib/transformers/list-item.spec.ts +48 -0
- package/src/lib/transformers/list-item.ts +37 -0
- package/src/lib/transformers/list.spec.ts +58 -0
- package/src/lib/transformers/list.ts +42 -0
- package/src/lib/transformers/mantra.spec.ts +58 -0
- package/src/lib/transformers/mantra.ts +28 -0
- package/src/lib/transformers/mention.ts +70 -0
- package/src/lib/transformers/paragraph.spec.ts +46 -0
- package/src/lib/transformers/paragraph.ts +26 -0
- package/src/lib/transformers/quote.spec.ts +42 -0
- package/src/lib/transformers/quote.ts +3 -0
- package/src/lib/transformers/quoted.ts +3 -0
- package/src/lib/transformers/recurse.ts +76 -0
- package/src/lib/transformers/reference.ts +3 -0
- package/src/lib/transformers/span.spec.ts +68 -0
- package/src/lib/transformers/span.ts +78 -0
- package/src/lib/transformers/split-at.ts +58 -0
- package/src/lib/transformers/split-block.ts +110 -0
- package/src/lib/transformers/split-content.ts +67 -0
- package/src/lib/transformers/split-insert.ts +76 -0
- package/src/lib/transformers/split-marks.ts +42 -0
- package/src/lib/transformers/split-node.ts +138 -0
- package/src/lib/transformers/table-body-data.spec.ts +44 -0
- package/src/lib/transformers/table-body-data.ts +29 -0
- package/src/lib/transformers/table-body-header.spec.ts +44 -0
- package/src/lib/transformers/table-body-header.ts +29 -0
- package/src/lib/transformers/table-body-row.spec.ts +44 -0
- package/src/lib/transformers/table-body-row.ts +29 -0
- package/src/lib/transformers/table.spec.ts +47 -0
- package/src/lib/transformers/table.ts +29 -0
- package/src/lib/transformers/trailer.spec.ts +43 -0
- package/src/lib/transformers/trailer.ts +26 -0
- package/src/lib/transformers/transformer.ts +25 -0
- package/src/lib/transformers/unknown.ts +8 -0
- package/src/lib/transformers/util.ts +20 -0
- package/src/lib/types.ts +10 -0
- package/src/ssr.ts +1 -0
- package/tsconfig.json +20 -0
- package/tsconfig.lib.json +29 -0
- package/tsconfig.spec.json +22 -0
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
createGraphQLClient,
|
|
5
|
+
getBibliographyEntry,
|
|
6
|
+
getGlossaryInstance,
|
|
7
|
+
getPassage,
|
|
8
|
+
getTranslationImprint,
|
|
9
|
+
getTranslationMetadataByUuid,
|
|
10
|
+
} from '@eightyfourthousand/client-graphql';
|
|
11
|
+
import type {
|
|
12
|
+
BibliographyEntryItem,
|
|
13
|
+
GlossaryTermInstance,
|
|
14
|
+
Imprint,
|
|
15
|
+
Passage,
|
|
16
|
+
TohokuCatalogEntry,
|
|
17
|
+
Work,
|
|
18
|
+
} from '@eightyfourthousand/data-access';
|
|
19
|
+
import {
|
|
20
|
+
ReactNode,
|
|
21
|
+
useCallback,
|
|
22
|
+
useEffect,
|
|
23
|
+
useMemo,
|
|
24
|
+
useRef,
|
|
25
|
+
useState,
|
|
26
|
+
} from 'react';
|
|
27
|
+
import { ReadonlyURLSearchParams, useSearchParams } from 'next/navigation';
|
|
28
|
+
import {
|
|
29
|
+
PANEL_NAMES,
|
|
30
|
+
PanelName,
|
|
31
|
+
PanelsState,
|
|
32
|
+
PanelState,
|
|
33
|
+
TabName,
|
|
34
|
+
} from './types';
|
|
35
|
+
import { HoverCardProvider } from './HoverCardProvider';
|
|
36
|
+
import { GatedFeature, useFeatureFlagEnabled } from '@eightyfourthousand/lib-instr';
|
|
37
|
+
import { useIsMobile } from '@eightyfourthousand/lib-utils';
|
|
38
|
+
import { RestrictionWarning } from './RestrictionWarning';
|
|
39
|
+
import { NavigationContext, DEFAULT_PANELS } from './NavigationContext';
|
|
40
|
+
|
|
41
|
+
export { NavigationContext, useNavigation } from './NavigationContext';
|
|
42
|
+
export type { NavigationState } from './NavigationContext';
|
|
43
|
+
|
|
44
|
+
const parsePanelParams = (
|
|
45
|
+
params: ReadonlyURLSearchParams,
|
|
46
|
+
): {
|
|
47
|
+
toh?: TohokuCatalogEntry;
|
|
48
|
+
panels: PanelsState;
|
|
49
|
+
} => {
|
|
50
|
+
const panels: PanelsState = { ...DEFAULT_PANELS };
|
|
51
|
+
|
|
52
|
+
for (const [key, value] of params.entries()) {
|
|
53
|
+
const match = value.match(/^(open|closed)(?::(.+))?$/);
|
|
54
|
+
if (match) {
|
|
55
|
+
const [state, tab, hash] = value.split(':');
|
|
56
|
+
const panelKey = key as PanelName;
|
|
57
|
+
if (!PANEL_NAMES.includes(panelKey)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
panels[panelKey] = {
|
|
61
|
+
open: state === 'open',
|
|
62
|
+
tab: tab as TabName | undefined,
|
|
63
|
+
hash: hash || undefined,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const toh = (params.get('toh') as TohokuCatalogEntry) || undefined;
|
|
69
|
+
|
|
70
|
+
return { toh, panels };
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const NavigationProvider = ({
|
|
74
|
+
uuid,
|
|
75
|
+
children,
|
|
76
|
+
}: {
|
|
77
|
+
uuid: string;
|
|
78
|
+
children: ReactNode;
|
|
79
|
+
}) => {
|
|
80
|
+
const graphqlClient = createGraphQLClient();
|
|
81
|
+
const query = useSearchParams();
|
|
82
|
+
const isMobile = useIsMobile();
|
|
83
|
+
const [panels, setPanels] = useState<PanelsState>(
|
|
84
|
+
parsePanelParams(query).panels || DEFAULT_PANELS,
|
|
85
|
+
);
|
|
86
|
+
const isPanelTransitioning = useRef(false);
|
|
87
|
+
const [toh, setToh] = useState<TohokuCatalogEntry | undefined>();
|
|
88
|
+
const [showOuterContent, setShowOuterContent] = useState(true);
|
|
89
|
+
const [hasTranslationContent, setHasTranslationContent] = useState(true);
|
|
90
|
+
const [imprint, setImprint] = useState<Imprint | undefined>();
|
|
91
|
+
const bibliographyCache = useRef<{ [uuid: string]: BibliographyEntryItem }>(
|
|
92
|
+
{},
|
|
93
|
+
);
|
|
94
|
+
const endnoteCache = useRef<{ [uuid: string]: Passage }>({});
|
|
95
|
+
const glossaryCache = useRef<{ [uuid: string]: GlossaryTermInstance }>({});
|
|
96
|
+
const passageCache = useRef<{ [uuid: string]: Passage }>({});
|
|
97
|
+
const workCache = useRef<{ [uuid: string]: Work }>({});
|
|
98
|
+
|
|
99
|
+
const fetchBibliographyEntry = useCallback(
|
|
100
|
+
async (uuid: string): Promise<BibliographyEntryItem | undefined> => {
|
|
101
|
+
if (!bibliographyCache.current) {
|
|
102
|
+
bibliographyCache.current = {};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (bibliographyCache.current[uuid]) {
|
|
106
|
+
return bibliographyCache.current[uuid];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const entry = await getBibliographyEntry({
|
|
110
|
+
client: graphqlClient,
|
|
111
|
+
uuid,
|
|
112
|
+
});
|
|
113
|
+
if (!entry) {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
bibliographyCache.current[uuid] = entry;
|
|
118
|
+
return entry;
|
|
119
|
+
},
|
|
120
|
+
[graphqlClient],
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const fetchEndNote = useCallback(
|
|
124
|
+
async (uuid: string): Promise<Passage | undefined> => {
|
|
125
|
+
if (!endnoteCache.current) {
|
|
126
|
+
endnoteCache.current = {};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (endnoteCache.current[uuid]) {
|
|
130
|
+
return endnoteCache.current[uuid];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const endnote = await getPassage({ client: graphqlClient, uuid });
|
|
134
|
+
if (!endnote) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
endnoteCache.current[uuid] = endnote;
|
|
139
|
+
return endnote;
|
|
140
|
+
},
|
|
141
|
+
[graphqlClient],
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const fetchGlossaryTerm = useCallback(
|
|
145
|
+
async (uuid: string) => {
|
|
146
|
+
if (!glossaryCache.current) {
|
|
147
|
+
glossaryCache.current = {};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (glossaryCache.current[uuid]) {
|
|
151
|
+
return glossaryCache.current[uuid];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const term = await getGlossaryInstance({ client: graphqlClient, uuid });
|
|
155
|
+
if (!term) {
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
glossaryCache.current[uuid] = term;
|
|
160
|
+
return term;
|
|
161
|
+
},
|
|
162
|
+
[graphqlClient],
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const fetchPassage = useCallback(
|
|
166
|
+
async (uuid: string): Promise<Passage | undefined> => {
|
|
167
|
+
if (!passageCache.current) {
|
|
168
|
+
passageCache.current = {};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (passageCache.current[uuid]) {
|
|
172
|
+
return passageCache.current[uuid];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const passage = await getPassage({ client: graphqlClient, uuid });
|
|
176
|
+
if (!passage) {
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
passageCache.current[uuid] = passage;
|
|
181
|
+
return passage;
|
|
182
|
+
},
|
|
183
|
+
[graphqlClient],
|
|
184
|
+
);
|
|
185
|
+
|
|
186
|
+
const fetchWork = useCallback(
|
|
187
|
+
async (uuid: string): Promise<Work | undefined> => {
|
|
188
|
+
if (!workCache.current) {
|
|
189
|
+
workCache.current = {};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (workCache.current[uuid]) {
|
|
193
|
+
return workCache.current[uuid];
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const work = await getTranslationMetadataByUuid({
|
|
197
|
+
client: graphqlClient,
|
|
198
|
+
uuid,
|
|
199
|
+
});
|
|
200
|
+
if (!work) {
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
workCache.current[uuid] = work;
|
|
205
|
+
return work;
|
|
206
|
+
},
|
|
207
|
+
[graphqlClient],
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
const updatePanel = useCallback(
|
|
211
|
+
({ name, state }: { name: PanelName; state: PanelState }) => {
|
|
212
|
+
const { open } = state;
|
|
213
|
+
isPanelTransitioning.current = true;
|
|
214
|
+
setPanels((prev) => {
|
|
215
|
+
const newPanels = {
|
|
216
|
+
...prev,
|
|
217
|
+
[name]: state,
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// On mobile, auto-close sidebars when navigating to other panels
|
|
221
|
+
if (isMobile && open) {
|
|
222
|
+
// If opening left panel with navigation, close right panel
|
|
223
|
+
if (name === 'left') {
|
|
224
|
+
newPanels.right = { ...prev.right, open: false };
|
|
225
|
+
}
|
|
226
|
+
// If opening right panel with navigation, close left panel
|
|
227
|
+
else if (name === 'right') {
|
|
228
|
+
newPanels.left = { ...prev.left, open: false };
|
|
229
|
+
}
|
|
230
|
+
// If opening main panel with navigation, close both sidebars
|
|
231
|
+
else if (name === 'main') {
|
|
232
|
+
newPanels.left = { ...prev.left, open: false };
|
|
233
|
+
newPanels.right = { ...prev.right, open: false };
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return newPanels;
|
|
238
|
+
});
|
|
239
|
+
},
|
|
240
|
+
[isMobile, hasTranslationContent],
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
useEffect(() => {
|
|
244
|
+
if (!toh && !panels) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
isPanelTransitioning.current = true;
|
|
249
|
+
const params = new URLSearchParams(window.location.search);
|
|
250
|
+
|
|
251
|
+
if (toh) {
|
|
252
|
+
params.set('toh', toh);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (panels) {
|
|
256
|
+
Object.entries(panels).forEach(([panelName, panelState]) => {
|
|
257
|
+
const { open, tab, hash } = panelState;
|
|
258
|
+
const openness = open ? 'open' : 'closed';
|
|
259
|
+
params.set(
|
|
260
|
+
panelName,
|
|
261
|
+
`${openness}${tab ? `:${tab}` : ''}${hash ? `:${hash}` : ''}`,
|
|
262
|
+
);
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const newUrl = `?${params.toString()}${window.location.hash}`;
|
|
267
|
+
window.history.replaceState(null, '', newUrl);
|
|
268
|
+
}, [toh, panels]);
|
|
269
|
+
|
|
270
|
+
useEffect(() => {
|
|
271
|
+
if (!uuid || !toh) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
(async () => {
|
|
276
|
+
const imprint = await getTranslationImprint({
|
|
277
|
+
client: graphqlClient,
|
|
278
|
+
uuid,
|
|
279
|
+
toh,
|
|
280
|
+
});
|
|
281
|
+
setImprint(imprint);
|
|
282
|
+
})();
|
|
283
|
+
}, [uuid, toh, graphqlClient]);
|
|
284
|
+
|
|
285
|
+
useEffect(() => {
|
|
286
|
+
if (isPanelTransitioning.current) {
|
|
287
|
+
isPanelTransitioning.current = false;
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const { panels: newPanels, toh: newToh } = parsePanelParams(query);
|
|
292
|
+
|
|
293
|
+
if (newPanels) {
|
|
294
|
+
setPanels(newPanels);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (newToh) {
|
|
298
|
+
setToh(newToh);
|
|
299
|
+
}
|
|
300
|
+
}, [query, parsePanelParams]);
|
|
301
|
+
|
|
302
|
+
const hasHoverCards = useFeatureFlagEnabled('translation-hover-cards');
|
|
303
|
+
|
|
304
|
+
useEffect(() => {
|
|
305
|
+
if (!hasTranslationContent) {
|
|
306
|
+
setPanels((prev) => {
|
|
307
|
+
if (!prev.right.open) {
|
|
308
|
+
return prev;
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
...prev,
|
|
312
|
+
right: { ...prev.right, open: false },
|
|
313
|
+
};
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}, [hasTranslationContent]);
|
|
317
|
+
|
|
318
|
+
const contextValue = useMemo(
|
|
319
|
+
() => ({
|
|
320
|
+
uuid,
|
|
321
|
+
imprint,
|
|
322
|
+
panels,
|
|
323
|
+
toh,
|
|
324
|
+
showOuterContent,
|
|
325
|
+
hasTranslationContent,
|
|
326
|
+
setToh,
|
|
327
|
+
setShowOuterContent,
|
|
328
|
+
setHasTranslationContent,
|
|
329
|
+
updatePanel,
|
|
330
|
+
fetchBibliographyEntry,
|
|
331
|
+
fetchEndNote,
|
|
332
|
+
fetchGlossaryTerm,
|
|
333
|
+
fetchPassage,
|
|
334
|
+
fetchWork,
|
|
335
|
+
}),
|
|
336
|
+
[
|
|
337
|
+
uuid,
|
|
338
|
+
imprint,
|
|
339
|
+
panels,
|
|
340
|
+
toh,
|
|
341
|
+
showOuterContent,
|
|
342
|
+
hasTranslationContent,
|
|
343
|
+
setToh,
|
|
344
|
+
setShowOuterContent,
|
|
345
|
+
setHasTranslationContent,
|
|
346
|
+
updatePanel,
|
|
347
|
+
fetchBibliographyEntry,
|
|
348
|
+
fetchEndNote,
|
|
349
|
+
fetchGlossaryTerm,
|
|
350
|
+
fetchPassage,
|
|
351
|
+
fetchWork,
|
|
352
|
+
],
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
return (
|
|
356
|
+
<NavigationContext.Provider value={contextValue}>
|
|
357
|
+
{hasHoverCards ? (
|
|
358
|
+
<HoverCardProvider>{children}</HoverCardProvider>
|
|
359
|
+
) : (
|
|
360
|
+
children
|
|
361
|
+
)}
|
|
362
|
+
<GatedFeature flag="show-restriction-warning">
|
|
363
|
+
<RestrictionWarning imprint={imprint} />
|
|
364
|
+
</GatedFeature>
|
|
365
|
+
</NavigationContext.Provider>
|
|
366
|
+
);
|
|
367
|
+
};
|
|
368
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ImageResponse } from 'next/og';
|
|
2
|
+
import {
|
|
3
|
+
createServerGraphQLClient,
|
|
4
|
+
getTranslationMetadataByUuid,
|
|
5
|
+
} from '@eightyfourthousand/client-graphql/ssr';
|
|
6
|
+
import { MainLogoSvg } from '@eightyfourthousand/design-system/ssr';
|
|
7
|
+
import { isUuid, parseToh } from '@eightyfourthousand/lib-utils';
|
|
8
|
+
import { cache } from 'react';
|
|
9
|
+
|
|
10
|
+
export const runtime = 'nodejs';
|
|
11
|
+
export const alt = '84000 Translation';
|
|
12
|
+
export const size = { width: 1200, height: 630 };
|
|
13
|
+
export const contentType = 'image/png';
|
|
14
|
+
|
|
15
|
+
export const OpenGraphImage = async ({
|
|
16
|
+
params,
|
|
17
|
+
}: {
|
|
18
|
+
params: Promise<{ slug: string }>;
|
|
19
|
+
}) => {
|
|
20
|
+
const { slug } = await params;
|
|
21
|
+
|
|
22
|
+
// Only fetch work metadata for valid UUIDs
|
|
23
|
+
let work = null;
|
|
24
|
+
if (isUuid(slug)) {
|
|
25
|
+
const client = await createServerGraphQLClient();
|
|
26
|
+
work = await cache(getTranslationMetadataByUuid)({
|
|
27
|
+
client,
|
|
28
|
+
uuid: slug,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const title = work?.title || '84000 Translation';
|
|
33
|
+
const toh = work?.toh.map(parseToh).join(', ') || '';
|
|
34
|
+
|
|
35
|
+
return new ImageResponse(
|
|
36
|
+
<div
|
|
37
|
+
style={{
|
|
38
|
+
display: 'flex',
|
|
39
|
+
flexDirection: 'column',
|
|
40
|
+
alignItems: 'center',
|
|
41
|
+
justifyContent: 'center',
|
|
42
|
+
width: '100%',
|
|
43
|
+
height: '100%',
|
|
44
|
+
backgroundColor: '#004570',
|
|
45
|
+
padding: '60px',
|
|
46
|
+
}}
|
|
47
|
+
>
|
|
48
|
+
<MainLogoSvg width={332} height={200} />
|
|
49
|
+
<div
|
|
50
|
+
style={{
|
|
51
|
+
color: 'white',
|
|
52
|
+
fontSize: 48,
|
|
53
|
+
fontWeight: 'bold',
|
|
54
|
+
textAlign: 'center',
|
|
55
|
+
marginTop: '40px',
|
|
56
|
+
maxWidth: '1000px',
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
{title}
|
|
60
|
+
</div>
|
|
61
|
+
{toh && (
|
|
62
|
+
<div
|
|
63
|
+
style={{
|
|
64
|
+
color: '#F18903',
|
|
65
|
+
fontSize: 32,
|
|
66
|
+
marginTop: '20px',
|
|
67
|
+
}}
|
|
68
|
+
>
|
|
69
|
+
{toh}
|
|
70
|
+
</div>
|
|
71
|
+
)}
|
|
72
|
+
</div>,
|
|
73
|
+
{ ...size },
|
|
74
|
+
);
|
|
75
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Skeleton } from '@eightyfourthousand/design-system';
|
|
2
|
+
|
|
3
|
+
export const PassageSkeleton = () => {
|
|
4
|
+
return (
|
|
5
|
+
<div className="flex gap-5 -ms-5 @c/sidebar:-ms-8">
|
|
6
|
+
<Skeleton className="h-4 w-6" />
|
|
7
|
+
<Skeleton className="h-32 grow" />
|
|
8
|
+
</div>
|
|
9
|
+
);
|
|
10
|
+
};
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Imprint } from '@eightyfourthousand/data-access';
|
|
4
|
+
import {
|
|
5
|
+
Accordion,
|
|
6
|
+
AccordionContent,
|
|
7
|
+
AccordionItem,
|
|
8
|
+
AccordionTrigger,
|
|
9
|
+
Button,
|
|
10
|
+
Dialog,
|
|
11
|
+
DialogClose,
|
|
12
|
+
DialogContent,
|
|
13
|
+
DialogFooter,
|
|
14
|
+
DialogHeader,
|
|
15
|
+
DialogTitle,
|
|
16
|
+
} from '@eightyfourthousand/design-system';
|
|
17
|
+
import { CircleAlertIcon, XIcon } from 'lucide-react';
|
|
18
|
+
import { useEffect, useState } from 'react';
|
|
19
|
+
|
|
20
|
+
const RESTRICTION_COOKIE_NAME = 'eft-restriction-warning-ignored';
|
|
21
|
+
|
|
22
|
+
export const getCookie = (name: string): string | undefined => {
|
|
23
|
+
const cookieValue = document.cookie
|
|
24
|
+
.split('; ')
|
|
25
|
+
.find((row) => row.startsWith(`${name}=`))
|
|
26
|
+
?.split('=')[1];
|
|
27
|
+
|
|
28
|
+
return decodeURIComponent(cookieValue || '');
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const setCookie = (name: string, value: string, days = 365) => {
|
|
32
|
+
const date = new Date();
|
|
33
|
+
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
|
|
34
|
+
const expires = `expires=${date.toUTCString()}`;
|
|
35
|
+
document.cookie = `${name}=${encodeURIComponent(value)}; ${expires}; path=/`;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const useRestrictionWarning = ({ imprint }: { imprint?: Imprint }) => {
|
|
39
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
40
|
+
const [shouldIgnore, setShouldIgnore] = useState(true);
|
|
41
|
+
const [toIgnore, setToIgnore] = useState<string[]>([]);
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const toIgnoreStr = getCookie(RESTRICTION_COOKIE_NAME) || '[]';
|
|
45
|
+
const toIgnore = JSON.parse(toIgnoreStr) || [];
|
|
46
|
+
setToIgnore(toIgnore);
|
|
47
|
+
}, []);
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (!imprint?.uuid) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
setShouldIgnore(toIgnore.includes(imprint.uuid));
|
|
55
|
+
}, [toIgnore, imprint]);
|
|
56
|
+
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (!shouldIgnore && imprint?.restriction) {
|
|
59
|
+
setIsOpen(true);
|
|
60
|
+
}
|
|
61
|
+
}, [shouldIgnore, imprint]);
|
|
62
|
+
|
|
63
|
+
const ignore = () => {
|
|
64
|
+
if (!imprint?.uuid) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const newToIgnore = [...toIgnore, imprint.uuid];
|
|
69
|
+
setToIgnore(newToIgnore);
|
|
70
|
+
setCookie(RESTRICTION_COOKIE_NAME, JSON.stringify(newToIgnore));
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
isOpen,
|
|
75
|
+
setIsOpen,
|
|
76
|
+
ignore,
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const RestrictionWarning = ({ imprint }: { imprint?: Imprint }) => {
|
|
81
|
+
const { isOpen, setIsOpen, ignore } = useRestrictionWarning({ imprint });
|
|
82
|
+
return (
|
|
83
|
+
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
|
84
|
+
<DialogContent
|
|
85
|
+
className="max-w-readable w-full font-serif"
|
|
86
|
+
showCloseButton={false}
|
|
87
|
+
>
|
|
88
|
+
<DialogHeader>
|
|
89
|
+
<div className="flex justify-between pb-4 text-destructive">
|
|
90
|
+
<CircleAlertIcon className="my-auto" />
|
|
91
|
+
<DialogTitle className="my-auto text-2xl">
|
|
92
|
+
Tantra Text Warning
|
|
93
|
+
</DialogTitle>
|
|
94
|
+
<DialogClose className="my-auto">
|
|
95
|
+
<XIcon />
|
|
96
|
+
</DialogClose>
|
|
97
|
+
</div>
|
|
98
|
+
</DialogHeader>
|
|
99
|
+
<p>
|
|
100
|
+
Readers are reminded that according to Vajrayāna Buddhist tradition
|
|
101
|
+
there are restrictions and commitments concerning tantra.
|
|
102
|
+
</p>
|
|
103
|
+
<p>
|
|
104
|
+
Practitioners who are not sure if they should read translations in
|
|
105
|
+
this section are advised to consult the authorities of their lineage.
|
|
106
|
+
</p>
|
|
107
|
+
<p>
|
|
108
|
+
The responsibility for reading these texts or sharing them with
|
|
109
|
+
others—and hence the consequences—lies in the hands of readers.
|
|
110
|
+
</p>
|
|
111
|
+
<Accordion type="single" collapsible>
|
|
112
|
+
<AccordionItem value="more-info">
|
|
113
|
+
<AccordionTrigger className="text-base">
|
|
114
|
+
About unrestricted access
|
|
115
|
+
</AccordionTrigger>
|
|
116
|
+
<AccordionContent className="space-y-2 leading-6">
|
|
117
|
+
<p>
|
|
118
|
+
The decision to publish tantra texts without restricted access
|
|
119
|
+
has been considered carefully. First of all, it should be noted
|
|
120
|
+
that all the original Tibetan texts of the Kangyur, including
|
|
121
|
+
those in this Tantra section, are in the public domain. Some of
|
|
122
|
+
the texts in this section (but by no means all of them) are
|
|
123
|
+
nevertheless, according to some traditions, only studied with
|
|
124
|
+
authorization and after suitable preliminaries.
|
|
125
|
+
</p>
|
|
126
|
+
<p>
|
|
127
|
+
It is true, of course, that a translation makes the content
|
|
128
|
+
accessible to a far greater number of people; 84000 has
|
|
129
|
+
therefore consulted many senior Buddhist teachers on this
|
|
130
|
+
question, and most of them felt that to publish the texts openly
|
|
131
|
+
is, on balance, the best solution. The alternatives would be not
|
|
132
|
+
to translate them at all (which would defeat the purposes of the
|
|
133
|
+
whole project), or to place some sort of restriction on their
|
|
134
|
+
access. Restricted access has been tried by some Buddhist book
|
|
135
|
+
publishers, and of course needs a system of administration,
|
|
136
|
+
judgment, and policing that is either a mere formality, or is
|
|
137
|
+
very difficult to implement. It would be even harder to
|
|
138
|
+
implement in the case of electronic texts—and even easier to
|
|
139
|
+
circumvent. Indeed, nowadays practically the whole range of
|
|
140
|
+
traditionally restricted Tibetan Buddhist material is already
|
|
141
|
+
available to anyone who looks for it, and is all too often
|
|
142
|
+
misrepresented, taken out of context, or its secret and esoteric
|
|
143
|
+
nature deliberately vaunted.
|
|
144
|
+
</p>
|
|
145
|
+
<p>
|
|
146
|
+
84000’s policy is to present carefully authenticated
|
|
147
|
+
translations in their proper setting of the whole body of
|
|
148
|
+
Buddhist sacred literature, and to trust the good sense of the
|
|
149
|
+
vast majority of readers not to misuse or misunderstand them.
|
|
150
|
+
Readers are reminded that according to Vajrayāna Buddhist
|
|
151
|
+
tradition there are restrictions and commitments concerning
|
|
152
|
+
tantra. Practitioners who are not sure if they should read
|
|
153
|
+
translations in this section are advised to consult the
|
|
154
|
+
authorities of their lineage. The responsibility, and hence
|
|
155
|
+
consequences, of reading these texts and/or sharing them with
|
|
156
|
+
others who may or may not fulfill the requirements lie in the
|
|
157
|
+
hands of readers.
|
|
158
|
+
</p>
|
|
159
|
+
</AccordionContent>
|
|
160
|
+
</AccordionItem>
|
|
161
|
+
</Accordion>
|
|
162
|
+
<DialogFooter>
|
|
163
|
+
<Button
|
|
164
|
+
className="font-sans"
|
|
165
|
+
variant="destructive"
|
|
166
|
+
onClick={() => {
|
|
167
|
+
setIsOpen(false);
|
|
168
|
+
ignore();
|
|
169
|
+
}}
|
|
170
|
+
>
|
|
171
|
+
Don't show again for this text
|
|
172
|
+
</Button>
|
|
173
|
+
</DialogFooter>
|
|
174
|
+
</DialogContent>
|
|
175
|
+
</Dialog>
|
|
176
|
+
);
|
|
177
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useInView } from 'motion/react';
|
|
4
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
5
|
+
import { useNavigation } from './NavigationProvider';
|
|
6
|
+
import { createGraphQLClient, getWorkFolios } from '@eightyfourthousand/client-graphql';
|
|
7
|
+
import type { Folio } from '@eightyfourthousand/data-access';
|
|
8
|
+
import { LabeledElement } from './LabeledElement';
|
|
9
|
+
import { PassageSkeleton } from './PassageSkeleton';
|
|
10
|
+
import { LotusPond } from '@eightyfourthousand/design-system';
|
|
11
|
+
|
|
12
|
+
const PAGE_SIZE = 10;
|
|
13
|
+
|
|
14
|
+
export const SourceReader = () => {
|
|
15
|
+
const [page, setPage] = useState(0);
|
|
16
|
+
const [hasMore, setHasMore] = useState(true);
|
|
17
|
+
const [folios, setFolios] = useState<Folio[]>([]);
|
|
18
|
+
|
|
19
|
+
const { toh, uuid } = useNavigation();
|
|
20
|
+
const loadMoreRef = useRef<HTMLDivElement>(null);
|
|
21
|
+
const shouldLoadMore = useInView(loadMoreRef);
|
|
22
|
+
const graphqlClient = createGraphQLClient();
|
|
23
|
+
|
|
24
|
+
const fetchMore = useCallback(async () => {
|
|
25
|
+
if (!toh || !uuid) return;
|
|
26
|
+
|
|
27
|
+
const folios = await getWorkFolios({
|
|
28
|
+
client: graphqlClient,
|
|
29
|
+
uuid,
|
|
30
|
+
toh,
|
|
31
|
+
page,
|
|
32
|
+
size: PAGE_SIZE,
|
|
33
|
+
});
|
|
34
|
+
if (folios.length) {
|
|
35
|
+
setPage((prevPage) => prevPage + 1);
|
|
36
|
+
setFolios((prevFolios) => [...prevFolios, ...folios]);
|
|
37
|
+
setHasMore(folios.length >= PAGE_SIZE);
|
|
38
|
+
}
|
|
39
|
+
}, [toh, uuid, page, graphqlClient]);
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (shouldLoadMore && hasMore) {
|
|
43
|
+
fetchMore();
|
|
44
|
+
}
|
|
45
|
+
}, [shouldLoadMore, hasMore, fetchMore]);
|
|
46
|
+
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
// Reset when uuid or toh changes
|
|
49
|
+
setFolios([]);
|
|
50
|
+
setPage(0);
|
|
51
|
+
setHasMore(true);
|
|
52
|
+
}, [toh, uuid]);
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<div className="pt-12 flex flex-col gap-5 mx-auto max-w-readable 2xl:max-w-380">
|
|
56
|
+
{folios.map((folio, index) => (
|
|
57
|
+
<LabeledElement
|
|
58
|
+
key={index}
|
|
59
|
+
id={folio.uuid}
|
|
60
|
+
label={`f.${folio.folio}.${folio.side}\nvol.${folio.volume}`}
|
|
61
|
+
className="mt-0.5"
|
|
62
|
+
contentType="source"
|
|
63
|
+
>
|
|
64
|
+
<div className="leading-7 font-tibetan text-lg 2xl:whitespace-pre-wrap whitespace-normal">
|
|
65
|
+
{folio.content}
|
|
66
|
+
</div>
|
|
67
|
+
</LabeledElement>
|
|
68
|
+
))}
|
|
69
|
+
<div ref={loadMoreRef} className="h-0" />
|
|
70
|
+
{hasMore ? (
|
|
71
|
+
<>
|
|
72
|
+
{Array.from({ length: 3 }).map((_, i) => (
|
|
73
|
+
<PassageSkeleton key={i} />
|
|
74
|
+
))}
|
|
75
|
+
</>
|
|
76
|
+
) : (
|
|
77
|
+
<div className="w-full pt-16 pb-6">
|
|
78
|
+
<LotusPond className="mx-auto w-96" />
|
|
79
|
+
</div>
|
|
80
|
+
)}
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
};
|