diff --git a/pkg/view/embed.html b/pkg/view/embed.html
new file mode 100644
index 0000000..18963b3
--- /dev/null
+++ b/pkg/view/embed.html
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ Embedded Interactive
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pkg/view/package.json b/pkg/view/package.json
index 8a0b3aa..461a71e 100644
--- a/pkg/view/package.json
+++ b/pkg/view/package.json
@@ -11,6 +11,10 @@
"dependencies": {
"@fortawesome/fontawesome-free": "^6.5.1",
"@solidjs/router": "^0.10.10",
+ "aplayer": "^1.10.1",
+ "artplayer": "^5.1.1",
+ "flv.js": "^1.6.2",
+ "hls.js": "^1.5.3",
"medium-zoom": "^1.1.0",
"solid-js": "^1.8.7",
"universal-cookie": "^7.0.2"
diff --git a/pkg/view/src/components/PostAttachments.tsx b/pkg/view/src/components/PostAttachments.tsx
index 2aad7b6..0379424 100644
--- a/pkg/view/src/components/PostAttachments.tsx
+++ b/pkg/view/src/components/PostAttachments.tsx
@@ -3,6 +3,93 @@ import mediumZoom from "medium-zoom";
import styles from "./PostAttachments.module.css";
+// @ts-ignore
+import APlayer from "aplayer";
+import Artplayer from "artplayer";
+import HlsJs from "hls.js";
+import FlvJs from "flv.js";
+
+import "aplayer/dist/APlayer.min.css";
+
+function Video({ url, ...rest }: any) {
+ let container: any;
+
+ function playM3u8(video: HTMLVideoElement, url: string, art: Artplayer) {
+ if (HlsJs.isSupported()) {
+ if (art.hls) art.hls.destroy();
+ const hls = new HlsJs();
+ hls.loadSource(url);
+ hls.attachMedia(video);
+ art.hls = hls;
+ art.on('destroy', () => hls.destroy());
+ } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
+ video.src = url;
+ } else {
+ art.notice.show = 'Unsupported playback format: m3u8';
+ }
+ }
+
+ function playFlv(video: HTMLVideoElement, url: string, art: Artplayer) {
+ if (FlvJs.isSupported()) {
+ if (art.flv) art.flv.destroy();
+ const flv = FlvJs.createPlayer({ type: 'flv', url });
+ flv.attachMediaElement(video);
+ flv.load();
+ art.flv = flv;
+ art.on('destroy', () => flv.destroy());
+ } else {
+ art.notice.show = 'Unsupported playback format: flv';
+ }
+ }
+
+ createEffect(() => {
+ new Artplayer({
+ container: container as HTMLDivElement,
+ url: url,
+ setting: true,
+ flip: true,
+ loop: true,
+ playbackRate: true,
+ aspectRatio: true,
+ subtitleOffset: true,
+ fullscreen: true,
+ fullscreenWeb: true,
+ screenshot: true,
+ autoPlayback: true,
+ airplay: true,
+ theme: "#49509e",
+ customType: {
+ m3u8: playM3u8,
+ flv: playFlv,
+ },
+ });
+ });
+
+ return (
+
+ );
+}
+
+function Audio({ url, caption, ...rest }: any) {
+ let container: any;
+
+ createEffect(() => {
+ new APlayer({
+ container: container as HTMLDivElement,
+ audio: [{
+ name: caption,
+ url: url,
+ theme: "#49509e"
+ }]
+ });
+ });
+
+ return (
+
+ );
+}
+
+
export default function PostAttachments(props: { attachments: any[] }) {
if (props.attachments.length <= 0) return null;
@@ -52,6 +139,12 @@ export default function PostAttachments(props: { attachments: any[] }) {
+
+
+
+
+
+
diff --git a/pkg/view/src/layouts/RootLayout.tsx b/pkg/view/src/layouts/RootLayout.tsx
index 3b44a28..1d24999 100644
--- a/pkg/view/src/layouts/RootLayout.tsx
+++ b/pkg/view/src/layouts/RootLayout.tsx
@@ -1,8 +1,8 @@
import Navbar from "./shared/Navbar.tsx";
import { readProfiles, useUserinfo } from "../stores/userinfo.tsx";
-import { createEffect, createSignal, Show } from "solid-js";
+import { createEffect, createMemo, createSignal, Show } from "solid-js";
import { readWellKnown } from "../stores/wellKnown.tsx";
-import { BeforeLeaveEventArgs, useBeforeLeave, useLocation, useNavigate } from "@solidjs/router";
+import { BeforeLeaveEventArgs, useBeforeLeave, useLocation, useNavigate, useSearchParams } from "@solidjs/router";
export default function RootLayout(props: any) {
const [ready, setReady] = createSignal(false);
@@ -12,6 +12,7 @@ export default function RootLayout(props: any) {
const navigate = useNavigate();
const userinfo = useUserinfo();
+ const [searchParams] = useSearchParams();
const location = useLocation();
createEffect(() => {
@@ -31,6 +32,14 @@ export default function RootLayout(props: any) {
useBeforeLeave((e: BeforeLeaveEventArgs) => keepGate(e.to.toString().split("?")[0], e));
+ const mainContentStyles = createMemo(() => {
+ if(!searchParams["noTitle"]) {
+ return "h-[calc(100vh-64px)] mt-[64px]"
+ } else {
+ return "h-[100vh]"
+ }
+ })
+
return (
@@ -39,8 +48,11 @@ export default function RootLayout(props: any) {
}>
-
- {props.children}
+
+
+
+
+ {props.children}
);
}
\ No newline at end of file