Skip to content

Commit

Permalink
Feat: New song format, update grouping, change from heading to index,…
Browse files Browse the repository at this point in the history
… textarea highlight, etc
  • Loading branch information
Vija02 committed Nov 14, 2024
1 parent 3aa891e commit ae29768
Show file tree
Hide file tree
Showing 17 changed files with 3,249 additions and 2,818 deletions.
10 changes: 9 additions & 1 deletion packages/ui/src/Slide/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Box, Text } from "@chakra-ui/react";

type PropTypes = {
heading?: string;
headingIsFaded?: boolean;
isActive?: boolean;
aspectRatio?: number;
onClick?: () => void;
Expand All @@ -10,6 +11,7 @@ type PropTypes = {

export const Slide = ({
heading,
headingIsFaded,
isActive,
aspectRatio = 16 / 9,
onClick,
Expand All @@ -18,7 +20,13 @@ export const Slide = ({
return (
<Box cursor={onClick ? "pointer" : "auto"} onClick={onClick}>
{heading && (
<Text fontWeight="bold" textTransform="uppercase" fontSize="xs" mb={1}>
<Text
fontWeight={headingIsFaded ? "normal" : "bold"}
textTransform="uppercase"
fontSize="xs"
mb={1}
color={headingIsFaded ? "gray.600" : "inherit"}
>
{heading}
</Text>
)}
Expand Down
7 changes: 7 additions & 0 deletions plugins/myworshiplist/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
"@repo/base-plugin": "*",
"@repo/ui": "*",
"@tanstack/react-query": "^5.59.16",
"@tiptap/core": "^2.9.1",
"@tiptap/extension-document": "^2.9.1",
"@tiptap/extension-history": "^2.9.1",
"@tiptap/extension-paragraph": "^2.9.1",
"@tiptap/extension-text": "^2.9.1",
"@tiptap/pm": "^2.9.1",
"@tiptap/react": "^2.9.1",
"@trpc/client": "^11.0.0-rc.593",
"@trpc/react-query": "^11.0.0-rc.593",
"@trpc/server": "^11.0.0-rc.593",
Expand Down
43 changes: 43 additions & 0 deletions plugins/myworshiplist/src/importer/myworshiplist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export const convertMWLData = (content: string) => {
return convertHeading(
removeAuxiliaryText(
cleanWhiteSpace(convertChords(content.split(/<br>|\n/gm) ?? [])),
),
).join("\n");
};

const convertChords = (content: string[]) => {
return content.map((val) => {
return val.match(/x[01]/) ? "." + val : val;
});
};
const cleanWhiteSpace = (content: string[]) => {
return content.map((x) => x.replace(/\s+/g, " ").trim());
};
const removeAuxiliaryText = (content: string[]) => {
return content.filter((songLine) => {
const match1 = songLine.match(
/^(\s*)repeat(\s*)(verse|bridge|pre-? ?chorus|chorus|end|tag|intro)? ?(\d+)?(.*)$/i,
);

if (match1 && match1?.length > 0) {
return false;
}

const match2 = songLine.match(/^(\s*)solo(\s*)$/i);

if (match2 && match2?.length > 0) {
return false;
}

return true;
});
};
const convertHeading = (content: string[]) => {
return content.map((val) => {
const matches = val.match(
/^(\s*)\[?(verse|bridge|pre-? ?chorus|chorus|end|ending|outro|tag|instrumental|interlude) ?(\d+)?\]?(\s*)$/i,
);
return matches ? "[" + val.replace(/[\[\]]/g, "") + "]" : val;
});
};
8 changes: 6 additions & 2 deletions plugins/myworshiplist/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
rendererWebComponentTag,
} from "./consts";
import { getSongData } from "./data";
import { convertMWLData } from "./importer/myworshiplist";
import { MyWorshipListData, PluginRendererData, Song } from "./types";

export const init = (serverPluginApi: ServerPluginApi) => {
Expand Down Expand Up @@ -87,7 +88,10 @@ const onPluginDataLoaded = (pluginInfo: ObjectToTypedMap<Plugin>) => {
if (!song.cachedData) {
const songData = await getSongData(song.id);

song.cachedData = songData;
song.cachedData = {
...songData,
content: convertMWLData(songData.content),
};
}
}
};
Expand All @@ -113,7 +117,7 @@ const onRendererDataCreated = (
rendererData: ObjectToTypedMap<Partial<PluginRendererData>>,
) => {
rendererData.set("songId", null);
rendererData.set("heading", null);
rendererData.set("currentIndex", null);

return {};
};
Expand Down
2 changes: 1 addition & 1 deletion plugins/myworshiplist/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,5 @@ export type SongSetting = z.infer<typeof songSettingValidator>;

export type PluginRendererData = {
songId: number | null;
heading: string | null;
currentIndex: number | null;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Box } from "@chakra-ui/react";
import Document from "@tiptap/extension-document";
import History from "@tiptap/extension-history";
import Paragraph from "@tiptap/extension-paragraph";
import TextExtension from "@tiptap/extension-text";
import { EditorContent, useEditor } from "@tiptap/react";
import { useEffect } from "react";

import { CustomDecorationPlugin } from "./customDecorationPlugin";

const SongEditEditor = ({
initialContent,
onChange,
}: {
initialContent: string;
onChange: (text: string) => void;
}) => {
const editor = useEditor({
onUpdate: (e) => {
onChange(e.editor.getText({ blockSeparator: "\n" }));
},
extensions: [
Document,
Paragraph.extend({
priority: 8000,
group: "block",
inline: false,
addProseMirrorPlugins() {
return [
...(this.parent?.() || []),
CustomDecorationPlugin({
name: this.name,
}),
];
},
}),
TextExtension,
History,
],
});

useEffect(() => {
if (editor && initialContent !== editor.getHTML()) {
editor?.commands.setContent(initialContent);
}
}, [editor, initialContent]);

return (
<Box
rounded="md"
border="1px solid"
borderColor="gray.200"
px={3}
py={2}
w="100%"
>
<EditorContent editor={editor} />
</Box>
);
};

export default SongEditEditor;
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {
ListItem,
OrderedList,
PopoverArrow,
PopoverBody,
PopoverCloseButton,
PopoverContent,
PopoverHeader,
Text,
} from "@chakra-ui/react";

export const SongEditInfo = () => {
return (
<PopoverContent
width="100%"
maxW="lg"
color="white"
bg="blue.800"
borderColor="blue.800"
>
<PopoverHeader pt={4} fontWeight="bold" border="0">
Formatting songs
</PopoverHeader>
<PopoverArrow bg="blue.800" />
<PopoverCloseButton />
<PopoverBody mb={3}>
We use quite a simple format to show songs inspired by OpenSong. <br />
<br />
Here are some of the basic rules: <br />
<OrderedList>
<ListItem>
Separate sections with square brackets(<Text as="b">[ ]</Text>) like{" "}
<Text as="b">[Verse 1]</Text>.
<br />
This can be anything from Verse, Chorus, Bridge, and any text you
like.
</ListItem>
<ListItem>
Use a single dash(<Text as="b">-</Text>) to split your section into
multiple slides.
</ListItem>
<ListItem>
Add a dot(<Text as="b">.</Text>) in front of a line to indicate that
it is a chord line.
<br />
Note: At this time, we do not support showing chords yet.
</ListItem>
</OrderedList>
</PopoverBody>
</PopoverContent>
);
};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { findChildren } from "@tiptap/core";
import { Node as ProsemirrorNode } from "@tiptap/pm/model";
import { Plugin, PluginKey } from "@tiptap/pm/state";
import { Decoration, DecorationSet } from "@tiptap/pm/view";

function getDecorations({ doc, name }: { doc: ProsemirrorNode; name: string }) {
const decorations: Decoration[] = [];

findChildren(doc, (node) => node.type.name === name).forEach((block) => {
if (block.node.textContent.startsWith(".")) {
const decoration = Decoration.inline(
block.pos,
block.pos + block.node.textContent.length + 1,
{
class: "chord",
},
);
decorations.push(decoration);
} else if (block.node.textContent === "-") {
const decoration = Decoration.inline(
block.pos,
block.pos + block.node.textContent.length + 1,
{
class: "lineBreak",
},
);
decorations.push(decoration);
} else if (
block.node.textContent.startsWith("[") &&
block.node.textContent.endsWith("]")
) {
const decoration = Decoration.inline(
block.pos,
block.pos + block.node.textContent.length + 1,
{
class: "heading",
},
);
decorations.push(decoration);
}
});

return DecorationSet.create(doc, decorations);
}

export function CustomDecorationPlugin({ name }: { name: string }) {
const customDecorationPlugin: Plugin<any> = new Plugin({
key: new PluginKey("customDecoration"),

state: {
init: (_, { doc }) =>
getDecorations({
doc,
name,
}),
apply: (transaction, decorationSet, oldState, newState) => {
const oldNodeName = oldState.selection.$head.parent.type.name;
const newNodeName = newState.selection.$head.parent.type.name;
const oldNodes = findChildren(
oldState.doc,
(node) => node.type.name === name,
);
const newNodes = findChildren(
newState.doc,
(node) => node.type.name === name,
);

if (
transaction.docChanged &&
// Apply decorations if:
// selection includes named node,
([oldNodeName, newNodeName].includes(name) ||
// OR transaction adds/removes named node,
newNodes.length !== oldNodes.length ||
// OR transaction has changes that completely encapsulte a node
// (for example, a transaction that affects the entire document).
// Such transactions can happen during collab syncing via y-prosemirror, for example.
transaction.steps.some((step) => {
// @ts-ignore
return (
// @ts-ignore
step.from !== undefined &&
// @ts-ignore
step.to !== undefined &&
oldNodes.some((node) => {
// @ts-ignore
return (
// @ts-ignore
node.pos >= step.from &&
// @ts-ignore
node.pos + node.node.nodeSize <= step.to
);
})
);
}))
) {
return getDecorations({
doc: transaction.doc,
name,
});
}

return decorationSet.map(transaction.mapping, transaction.doc);
},
},

props: {
decorations(state) {
return customDecorationPlugin.getState(state);
},
},
});

return customDecorationPlugin;
}
Loading

0 comments on commit ae29768

Please sign in to comment.