@freqhole/playlistz 0.0.1
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/.changeset/config.json +11 -0
- package/.changeset/nice-wolves-thank.md +5 -0
- package/.freqhole-versions.json +4 -0
- package/.github/copilot-instructions.md +201 -0
- package/.github/workflows/changesets.yml +50 -0
- package/.github/workflows/npm-publish.yml +124 -0
- package/.github/workflows/pr-checks.yml +103 -0
- package/README.md +30 -0
- package/build-component.js +141 -0
- package/build-zip-bundle-lib.js +44 -0
- package/config/playwright.config.ts +47 -0
- package/config/vite.config.ts +44 -0
- package/config/vitest.config.ts +39 -0
- package/dist/assets/automerge_wasm_bg-Cik4BF9l.wasm +0 -0
- package/dist/assets/index-CbOXzGiA.js +216 -0
- package/dist/assets/index-CbOXzGiA.js.map +1 -0
- package/dist/assets/index-TvJ6RFpy.css +1 -0
- package/dist/assets/midden-DceCrT_L.js +2 -0
- package/dist/assets/midden-DceCrT_L.js.map +1 -0
- package/dist/assets/midden_bg-BLhfGIU-.wasm +0 -0
- package/dist/index.html +55 -0
- package/dist/sw.js +134 -0
- package/docs/AUTOMERGE_P2P_PLAN.md +233 -0
- package/docs/COLLABORATIVE_SHARING_PLAN.md +188 -0
- package/docs/E2E_TESTID_PLAN.md +234 -0
- package/docs/IROH_P2P_PLAN.md +302 -0
- package/docs/ROADMAP.md +695 -0
- package/docs/TODO.md +167 -0
- package/docs/bundle-embedding-plan.md +134 -0
- package/docs/standalone-refactor.md +184 -0
- package/e2e/all-playlists.spec.ts +220 -0
- package/e2e/audio-player.spec.ts +226 -0
- package/e2e/collaborative-features.spec.ts +229 -0
- package/e2e/contexts.ts +238 -0
- package/e2e/edit-panel.spec.ts +87 -0
- package/e2e/fixtures/bare-glitch-1s.m4a +0 -0
- package/e2e/fixtures/bare-glitch-1s.mp3 +0 -0
- package/e2e/fixtures/bare-glitch-1s.ogg +0 -0
- package/e2e/fixtures/chord-stack-3s.wav +0 -0
- package/e2e/fixtures/cover-anim.gif +0 -0
- package/e2e/fixtures/cover-blue.png +0 -0
- package/e2e/fixtures/cover-checkers.png +0 -0
- package/e2e/fixtures/cover-gradient.jpg +0 -0
- package/e2e/fixtures/cover-mono.gif +0 -0
- package/e2e/fixtures/cover-noise.png +0 -0
- package/e2e/fixtures/cover-plasma.webp +0 -0
- package/e2e/fixtures/cover-portrait.jpg +0 -0
- package/e2e/fixtures/cover-red.png +0 -0
- package/e2e/fixtures/cover-thumb.jpg +0 -0
- package/e2e/fixtures/cover-wide.webp +0 -0
- package/e2e/fixtures/generate.mjs +257 -0
- package/e2e/fixtures/long-drone-90s.mp3 +0 -0
- package/e2e/fixtures/noisy-binaural-8s.mp3 +0 -0
- package/e2e/fixtures/tagged-a3-4s.m4a +0 -0
- package/e2e/fixtures/tagged-a3-4s.mp3 +0 -0
- package/e2e/fixtures/tagged-a3-4s.ogg +0 -0
- package/e2e/fixtures/tagged-c5-3s.m4a +0 -0
- package/e2e/fixtures/tagged-c5-3s.mp3 +0 -0
- package/e2e/fixtures/tagged-c5-3s.ogg +0 -0
- package/e2e/fixtures/tagged-f4-6s.m4a +0 -0
- package/e2e/fixtures/tagged-f4-6s.mp3 +0 -0
- package/e2e/fixtures/tagged-f4-6s.ogg +0 -0
- package/e2e/fixtures/tone-220hz-10s.wav +0 -0
- package/e2e/fixtures/tone-440hz-2s.wav +0 -0
- package/e2e/fixtures/tone-880hz-5s.wav +0 -0
- package/e2e/fixtures/tone-stereo-3s.wav +0 -0
- package/e2e/fixtures/user-provided/README.md +1 -0
- package/e2e/helpers/app.ts +143 -0
- package/e2e/helpers/hooks.ts +133 -0
- package/e2e/helpers/index.ts +12 -0
- package/e2e/helpers/media.ts +125 -0
- package/e2e/helpers.ts +10 -0
- package/e2e/p2p-collaboration.spec.ts +356 -0
- package/e2e/p2p-multi-peer.spec.ts +723 -0
- package/e2e/p2p-states.spec.ts +302 -0
- package/e2e/playback.spec.ts +56 -0
- package/e2e/playlist-crud.spec.ts +126 -0
- package/e2e/share-link-autoplay.spec.ts +129 -0
- package/e2e/sharing-access.spec.ts +205 -0
- package/e2e/sharing.spec.ts +195 -0
- package/e2e/song-cache-state.spec.ts +202 -0
- package/e2e/zip-bundle.spec.ts +855 -0
- package/eslint.config.js +114 -0
- package/index.html +54 -0
- package/package.json +119 -0
- package/public/sw.js +134 -0
- package/scripts/use-local.mjs +37 -0
- package/scripts/use-published.mjs +37 -0
- package/src/App.tsx +9 -0
- package/src/cli/check.ts +164 -0
- package/src/cli/generate.ts +184 -0
- package/src/cli/http.ts +88 -0
- package/src/cli/index.ts +65 -0
- package/src/cli/init.ts +18 -0
- package/src/components/AllPlaylistsPanel.tsx +713 -0
- package/src/components/AudioPlayer.tsx +122 -0
- package/src/components/MarqueeText.tsx +101 -0
- package/src/components/PlaylistCoverModal.tsx +519 -0
- package/src/components/PlaylistEditPanel.tsx +803 -0
- package/src/components/PlaylistSharePanel.tsx +1020 -0
- package/src/components/ShareLinkKnockPanel.tsx +144 -0
- package/src/components/SharePanel.tsx +584 -0
- package/src/components/SongEditModal.tsx +453 -0
- package/src/components/SongEditPanel.tsx +578 -0
- package/src/components/SongRow.tsx +689 -0
- package/src/components/index.tsx +494 -0
- package/src/components/playlist/index.tsx +1203 -0
- package/src/context/PlaylistzContext.tsx +74 -0
- package/src/dev-hooks.ts +35 -0
- package/src/hooks/createDocIndexQuery.ts +53 -0
- package/src/hooks/createDocStore.test.ts +303 -0
- package/src/hooks/createDocStore.ts +90 -0
- package/src/hooks/useDragAndDrop.test.ts +474 -0
- package/src/hooks/useDragAndDrop.ts +400 -0
- package/src/hooks/useImageModal.test.ts +174 -0
- package/src/hooks/useImageModal.ts +201 -0
- package/src/hooks/usePlaylistManager.test.ts +453 -0
- package/src/hooks/usePlaylistManager.ts +685 -0
- package/src/hooks/usePlaylistsQuery.test.tsx +120 -0
- package/src/hooks/usePlaylistsQuery.ts +44 -0
- package/src/hooks/useSongState.test.ts +236 -0
- package/src/hooks/useSongState.ts +114 -0
- package/src/hooks/useUIState.ts +71 -0
- package/src/index.tsx +18 -0
- package/src/services/audioService.dev.ts +22 -0
- package/src/services/audioService.test.ts +1226 -0
- package/src/services/audioService.ts +1395 -0
- package/src/services/automergeRepo.test.ts +269 -0
- package/src/services/automergeRepo.ts +226 -0
- package/src/services/blobTransferService.dev.ts +119 -0
- package/src/services/blobTransferService.test.ts +441 -0
- package/src/services/blobTransferService.ts +702 -0
- package/src/services/docIndexService.test.ts +179 -0
- package/src/services/docIndexService.ts +118 -0
- package/src/services/fileProcessingService.test.ts +554 -0
- package/src/services/fileProcessingService.ts +239 -0
- package/src/services/imageService.test.ts +701 -0
- package/src/services/imageService.ts +365 -0
- package/src/services/indexedDBService.integration.test.ts +104 -0
- package/src/services/indexedDBService.test.ts +202 -0
- package/src/services/indexedDBService.ts +436 -0
- package/src/services/offlineService.test.ts +661 -0
- package/src/services/offlineService.ts +382 -0
- package/src/services/p2pService.test.ts +305 -0
- package/src/services/p2pService.ts +344 -0
- package/src/services/playlistDocService.test.ts +448 -0
- package/src/services/playlistDocService.ts +707 -0
- package/src/services/playlistDownloadService.test.ts +674 -0
- package/src/services/playlistDownloadService.ts +389 -0
- package/src/services/sharingService.test.ts +812 -0
- package/src/services/sharingService.ts +1073 -0
- package/src/services/sharingState.ts +161 -0
- package/src/services/songReactivity.test.ts +620 -0
- package/src/services/songReactivity.ts +145 -0
- package/src/services/standaloneService.test.ts +1025 -0
- package/src/services/standaloneService.ts +588 -0
- package/src/services/streamingAudioService.test.ts +275 -0
- package/src/services/streamingAudioService.ts +166 -0
- package/src/styles.css +428 -0
- package/src/test-setup.ts +547 -0
- package/src/types/global.d.ts +40 -0
- package/src/types/playlist.ts +99 -0
- package/src/utils/hashUtils.ts +41 -0
- package/src/utils/log.ts +97 -0
- package/src/utils/m3u.test.ts +172 -0
- package/src/utils/m3u.ts +136 -0
- package/src/utils/mockData.ts +166 -0
- package/src/utils/standaloneTemplates.test.ts +175 -0
- package/src/utils/standaloneTemplates.ts +83 -0
- package/src/utils/swTemplate.ts +84 -0
- package/src/utils/timeUtils.ts +166 -0
- package/src/utils/typeGuards.ts +171 -0
- package/src/web-component.tsx +98 -0
- package/src/zip-bundle/index.ts +7 -0
- package/src/zip-bundle/m3u.ts +45 -0
- package/src/zip-bundle/types.ts +50 -0
- package/src/zip-bundle/utils.ts +33 -0
- package/src/zip-bundle/zipBuilder.ts +309 -0
- package/tailwind.config.js +55 -0
- package/tsconfig.json +43 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// modal overlay shown when a share link requires a knock before syncing.
|
|
2
|
+
// lets the user write a message to the owner and send the knock.
|
|
3
|
+
import { createSignal, Show } from "solid-js";
|
|
4
|
+
import { knockForDocAccess } from "../services/sharingService.js";
|
|
5
|
+
import { ensureSharingReady } from "../services/sharingService.js";
|
|
6
|
+
|
|
7
|
+
interface ShareLinkKnockPanelProps {
|
|
8
|
+
ownerNodeId: string;
|
|
9
|
+
docId: string;
|
|
10
|
+
title?: string;
|
|
11
|
+
ownerName?: string;
|
|
12
|
+
onAccepted: (docId: string) => void;
|
|
13
|
+
onDismiss: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function ShareLinkKnockPanel(props: ShareLinkKnockPanelProps) {
|
|
17
|
+
const [message, setMessage] = createSignal("");
|
|
18
|
+
const [status, setStatus] = createSignal<
|
|
19
|
+
"idle" | "sending" | "pending" | "denied" | "error"
|
|
20
|
+
>("idle");
|
|
21
|
+
const [errorText, setErrorText] = createSignal("");
|
|
22
|
+
|
|
23
|
+
const handleSendKnock = async () => {
|
|
24
|
+
setStatus("sending");
|
|
25
|
+
setErrorText("");
|
|
26
|
+
try {
|
|
27
|
+
await ensureSharingReady();
|
|
28
|
+
const result = await knockForDocAccess(
|
|
29
|
+
props.ownerNodeId,
|
|
30
|
+
props.docId,
|
|
31
|
+
message(),
|
|
32
|
+
props.title
|
|
33
|
+
);
|
|
34
|
+
if (result.status === "accepted") {
|
|
35
|
+
props.onAccepted(props.docId);
|
|
36
|
+
} else if (result.status === "denied") {
|
|
37
|
+
setStatus("denied");
|
|
38
|
+
} else {
|
|
39
|
+
setStatus("pending");
|
|
40
|
+
}
|
|
41
|
+
} catch (err) {
|
|
42
|
+
setErrorText(err instanceof Error ? err.message : "knock failed");
|
|
43
|
+
setStatus("error");
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const ownerLabel = () =>
|
|
48
|
+
props.ownerName || props.ownerNodeId.slice(0, 12) + "...";
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<div
|
|
52
|
+
data-testid="share-knock-panel"
|
|
53
|
+
class="fixed inset-0 flex items-center justify-center z-50 bg-black/80 backdrop-blur-sm"
|
|
54
|
+
>
|
|
55
|
+
<div class="bg-black border border-gray-700 p-6 max-w-sm w-full mx-4 space-y-4 font-mono">
|
|
56
|
+
<h2 class="text-white text-sm font-medium">knock to access playlist</h2>
|
|
57
|
+
|
|
58
|
+
<div class="space-y-1">
|
|
59
|
+
<p class="text-gray-400 text-xs">
|
|
60
|
+
<span class="text-gray-200">{ownerLabel()}</span> has shared{" "}
|
|
61
|
+
<Show when={props.title} fallback={<span>a playlist</span>}>
|
|
62
|
+
<span class="text-white">"{props.title}"</span>
|
|
63
|
+
</Show>{" "}
|
|
64
|
+
with access control enabled. send a knock to request access.
|
|
65
|
+
</p>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<Show
|
|
69
|
+
when={
|
|
70
|
+
status() === "idle" ||
|
|
71
|
+
status() === "sending" ||
|
|
72
|
+
status() === "error"
|
|
73
|
+
}
|
|
74
|
+
>
|
|
75
|
+
<div class="space-y-2">
|
|
76
|
+
<label class="block text-xs text-gray-400">
|
|
77
|
+
message to owner (optional)
|
|
78
|
+
</label>
|
|
79
|
+
<textarea
|
|
80
|
+
data-testid="input-knock-message"
|
|
81
|
+
value={message()}
|
|
82
|
+
onInput={(e) => setMessage(e.currentTarget.value)}
|
|
83
|
+
placeholder="hi, found your link and would love to listen..."
|
|
84
|
+
rows="3"
|
|
85
|
+
disabled={status() === "sending"}
|
|
86
|
+
class="w-full bg-black text-white text-xs border border-gray-700 px-2 py-1.5 focus:outline-none focus:border-magenta-500 resize-none disabled:opacity-50"
|
|
87
|
+
/>
|
|
88
|
+
<Show when={errorText()}>
|
|
89
|
+
<p class="text-red-400 text-xs">{errorText()}</p>
|
|
90
|
+
</Show>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<div class="flex gap-2">
|
|
94
|
+
<button
|
|
95
|
+
data-testid="btn-send-knock"
|
|
96
|
+
onClick={() => void handleSendKnock()}
|
|
97
|
+
disabled={status() === "sending"}
|
|
98
|
+
class="flex-1 px-3 py-2 bg-magenta-500 hover:bg-magenta-600 disabled:bg-magenta-400 text-white text-sm transition-colors"
|
|
99
|
+
>
|
|
100
|
+
{status() === "sending" ? "sending..." : "send knock"}
|
|
101
|
+
</button>
|
|
102
|
+
<button
|
|
103
|
+
onClick={props.onDismiss}
|
|
104
|
+
disabled={status() === "sending"}
|
|
105
|
+
class="px-3 py-2 border border-gray-700 hover:border-gray-500 text-gray-400 hover:text-white text-sm transition-colors"
|
|
106
|
+
>
|
|
107
|
+
cancel
|
|
108
|
+
</button>
|
|
109
|
+
</div>
|
|
110
|
+
</Show>
|
|
111
|
+
|
|
112
|
+
<Show when={status() === "pending"}>
|
|
113
|
+
<div class="space-y-3">
|
|
114
|
+
<p class="text-gray-300 text-xs">
|
|
115
|
+
knock sent - waiting for{" "}
|
|
116
|
+
<span class="text-white">{ownerLabel()}</span> to accept. you can
|
|
117
|
+
dismiss this and try again later.
|
|
118
|
+
</p>
|
|
119
|
+
<button
|
|
120
|
+
onClick={props.onDismiss}
|
|
121
|
+
class="w-full px-3 py-2 border border-gray-700 hover:border-gray-500 text-gray-400 hover:text-white text-sm transition-colors"
|
|
122
|
+
>
|
|
123
|
+
dismiss
|
|
124
|
+
</button>
|
|
125
|
+
</div>
|
|
126
|
+
</Show>
|
|
127
|
+
|
|
128
|
+
<Show when={status() === "denied"}>
|
|
129
|
+
<div class="space-y-3">
|
|
130
|
+
<p class="text-red-400 text-xs">
|
|
131
|
+
access denied by the playlist owner.
|
|
132
|
+
</p>
|
|
133
|
+
<button
|
|
134
|
+
onClick={props.onDismiss}
|
|
135
|
+
class="w-full px-3 py-2 border border-gray-700 hover:border-gray-500 text-gray-400 hover:text-white text-sm transition-colors"
|
|
136
|
+
>
|
|
137
|
+
dismiss
|
|
138
|
+
</button>
|
|
139
|
+
</div>
|
|
140
|
+
</Show>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
);
|
|
144
|
+
}
|