feat: deeplink & vercel
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
"slug": "musicland",
|
"slug": "musicland",
|
||||||
"name": "MusicLand",
|
"name": "MusicLand",
|
||||||
"scheme": "musicland",
|
"scheme": "musicland",
|
||||||
|
"deeplinks": ["musicland://"],
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"icon": "./assets/icon.png",
|
"icon": "./assets/icon.png",
|
||||||
"backgroundColor": "#0F0C14",
|
"backgroundColor": "#0F0C14",
|
||||||
@@ -25,7 +26,7 @@
|
|||||||
"usesAppleSignIn": true,
|
"usesAppleSignIn": true,
|
||||||
"requireFullScreen": true,
|
"requireFullScreen": true,
|
||||||
"userInterfaceStyle": "dark",
|
"userInterfaceStyle": "dark",
|
||||||
"associatedDomains": ["applinks:minuit.starter"],
|
"associatedDomains": ["applinks:musicland-one.vercel.app"],
|
||||||
"bundleIdentifier": "com.omedis.musicland.ai",
|
"bundleIdentifier": "com.omedis.musicland.ai",
|
||||||
"infoPlist": {
|
"infoPlist": {
|
||||||
"NSMicrophoneUsageDescription": "MusicLand uses the microphone to record your voice and audio so you can create and collaborate on music projects.",
|
"NSMicrophoneUsageDescription": "MusicLand uses the microphone to record your voice and audio so you can create and collaborate on music projects.",
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 281 KiB After Width: | Height: | Size: 86 KiB |
@@ -39,7 +39,9 @@ const ShareModal = ({ payload }) => {
|
|||||||
const url = payload?.url ?? musiclandShareUrl;
|
const url = payload?.url ?? musiclandShareUrl;
|
||||||
const shareTitle = payload?.shareTitle ?? heading;
|
const shareTitle = payload?.shareTitle ?? heading;
|
||||||
const shareMessage = payload?.shareMessage ?? musiclandShareMessage;
|
const shareMessage = payload?.shareMessage ?? musiclandShareMessage;
|
||||||
const linkLabel = payload?.linkLabel ?? url;
|
const copyUrl =
|
||||||
|
payload?.copyUrl ?? payload?.qrUrl ?? payload?.url ?? musiclandShareUrl;
|
||||||
|
const linkLabel = payload?.linkLabel ?? copyUrl;
|
||||||
const sectionTitle = payload?.sectionTitle ?? "Partager sur...";
|
const sectionTitle = payload?.sectionTitle ?? "Partager sur...";
|
||||||
const qrTitle = payload?.qrTitle ?? "Scannez le QR-code";
|
const qrTitle = payload?.qrTitle ?? "Scannez le QR-code";
|
||||||
const qrUrl = payload?.qrUrl ?? musiclandShareUrl;
|
const qrUrl = payload?.qrUrl ?? musiclandShareUrl;
|
||||||
@@ -140,13 +142,13 @@ const ShareModal = ({ payload }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isWeb && typeof navigator !== "undefined" && navigator.clipboard) {
|
if (isWeb && typeof navigator !== "undefined" && navigator.clipboard) {
|
||||||
await navigator.clipboard.writeText(url);
|
await navigator.clipboard.writeText(copyUrl);
|
||||||
} else {
|
} else {
|
||||||
const Clipboard = await import("expo-clipboard");
|
const Clipboard = await import("expo-clipboard");
|
||||||
if (typeof Clipboard?.setStringAsync === "function") {
|
if (typeof Clipboard?.setStringAsync === "function") {
|
||||||
await Clipboard.setStringAsync(url);
|
await Clipboard.setStringAsync(copyUrl);
|
||||||
} else if (typeof Clipboard?.default?.setStringAsync === "function") {
|
} else if (typeof Clipboard?.default?.setStringAsync === "function") {
|
||||||
await Clipboard.default.setStringAsync(url);
|
await Clipboard.default.setStringAsync(copyUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +159,7 @@ const ShareModal = ({ payload }) => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("share.copy.failed", error);
|
console.error("share.copy.failed", error);
|
||||||
}
|
}
|
||||||
}, [url]);
|
}, [copyUrl]);
|
||||||
|
|
||||||
const handleSystemShare = useCallback(async () => {
|
const handleSystemShare = useCallback(async () => {
|
||||||
if (Platform.OS === "web" && typeof navigator !== "undefined") {
|
if (Platform.OS === "web" && typeof navigator !== "undefined") {
|
||||||
|
|||||||
@@ -102,19 +102,42 @@ const UniversalLinkProvider = ({ children }) => {
|
|||||||
}, [isFullyLoaded, pendingMusicId]);
|
}, [isFullyLoaded, pendingMusicId]);
|
||||||
|
|
||||||
const handleParams = (path, _queryParams = {}) => {
|
const handleParams = (path, _queryParams = {}) => {
|
||||||
if (typeof path === "string" && path.length > 0) {
|
if ((typeof path === "string" && path.length > 0) || _queryParams?.music) {
|
||||||
const normalized = path.replace(/^\/+/, "");
|
const normalized = typeof path === "string" ? path.replace(/^\/+/, "") : "";
|
||||||
const [first, second] = normalized.split("/");
|
const segments = normalized
|
||||||
if (first?.toLowerCase() === "music" && second) {
|
.split("/")
|
||||||
|
.map((segment) => segment.trim())
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
const musicIndex = segments.findIndex(
|
||||||
|
(segment) => segment?.toLowerCase() === "music"
|
||||||
|
);
|
||||||
|
|
||||||
|
let musicIdentifier = null;
|
||||||
|
if (musicIndex !== -1 && segments[musicIndex + 1]) {
|
||||||
|
musicIdentifier = segments[musicIndex + 1];
|
||||||
|
} else if (segments.length === 1 && segments[0]) {
|
||||||
|
musicIdentifier = segments[0];
|
||||||
|
} else if (typeof _queryParams?.music === "string") {
|
||||||
|
musicIdentifier = _queryParams.music;
|
||||||
|
} else if (typeof _queryParams?.projectId === "string") {
|
||||||
|
musicIdentifier = _queryParams.projectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (musicIdentifier) {
|
||||||
try {
|
try {
|
||||||
setPendingMusicId(decodeURIComponent(second));
|
setPendingMusicId(decodeURIComponent(musicIdentifier));
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
setPendingMusicId(second);
|
setPendingMusicId(musicIdentifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isWeb) {
|
||||||
|
setTimeout(cleanURL, 1500);
|
||||||
|
} else {
|
||||||
cleanURL();
|
cleanURL();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const cleanURL = () => {
|
const cleanURL = () => {
|
||||||
@@ -124,7 +147,8 @@ const UniversalLinkProvider = ({ children }) => {
|
|||||||
// console.log(url);
|
// console.log(url);
|
||||||
|
|
||||||
url.search = "";
|
url.search = "";
|
||||||
window.history.replaceState({}, document.title, url.origin.toString());
|
const next = `${url.origin}${url.pathname}${url.hash || ""}`;
|
||||||
|
window.history.replaceState({}, document.title, next);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+49
-1
@@ -1,22 +1,65 @@
|
|||||||
import { SheetManager } from "react-native-actions-sheet";
|
import { SheetManager } from "react-native-actions-sheet";
|
||||||
|
|
||||||
|
import appJson from "../../app.json";
|
||||||
import {
|
import {
|
||||||
musiclandShareHeading,
|
musiclandShareHeading,
|
||||||
musiclandShareMessage,
|
musiclandShareMessage,
|
||||||
musiclandShareUrl,
|
musiclandShareUrl,
|
||||||
} from "../data";
|
} from "../data";
|
||||||
|
|
||||||
|
const APP_SCHEME = appJson?.expo?.scheme || "musicland";
|
||||||
|
const APP_SCHEME_BASE = `${APP_SCHEME}://app`;
|
||||||
|
|
||||||
const defaultPayload = {
|
const defaultPayload = {
|
||||||
heading: musiclandShareHeading,
|
heading: musiclandShareHeading,
|
||||||
url: musiclandShareUrl,
|
url: musiclandShareUrl,
|
||||||
shareTitle: "MusicLand",
|
shareTitle: "MusicLand",
|
||||||
shareMessage: musiclandShareMessage,
|
shareMessage: musiclandShareMessage,
|
||||||
qrUrl: musiclandShareUrl,
|
qrUrl: musiclandShareUrl,
|
||||||
|
copyUrl: musiclandShareUrl,
|
||||||
|
linkLabel: musiclandShareUrl,
|
||||||
|
appLink: APP_SCHEME_BASE,
|
||||||
};
|
};
|
||||||
|
|
||||||
const trimTrailingSlash = (value) =>
|
const trimTrailingSlash = (value) =>
|
||||||
typeof value === "string" ? value.replace(/\/+$/, "") : "";
|
typeof value === "string" ? value.replace(/\/+$/, "") : "";
|
||||||
|
|
||||||
|
const trimLeadingSlash = (value) =>
|
||||||
|
typeof value === "string" ? value.replace(/^\/+/, "") : "";
|
||||||
|
|
||||||
|
const buildQueryString = (params = {}) => {
|
||||||
|
const entries = Object.entries(params).filter(
|
||||||
|
([, value]) => value !== undefined && value !== null && value !== ""
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!entries.length) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const searchParams = new URLSearchParams();
|
||||||
|
entries.forEach(([key, value]) => {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
value.forEach((item) => {
|
||||||
|
searchParams.append(key, `${item}`);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
searchParams.append(key, `${value}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const query = searchParams.toString();
|
||||||
|
return query ? `?${query}` : "";
|
||||||
|
};
|
||||||
|
|
||||||
|
const createSchemeDeepLink = (path = "", params = {}) => {
|
||||||
|
const sanitizedPath = trimLeadingSlash(path);
|
||||||
|
const basePath = sanitizedPath
|
||||||
|
? `${APP_SCHEME_BASE}/${sanitizedPath}`
|
||||||
|
: APP_SCHEME_BASE;
|
||||||
|
|
||||||
|
return `${basePath}${buildQueryString(params)}`;
|
||||||
|
};
|
||||||
|
|
||||||
const resolveBaseShareUrl = () => {
|
const resolveBaseShareUrl = () => {
|
||||||
if (typeof window !== "undefined" && window.location?.origin) {
|
if (typeof window !== "undefined" && window.location?.origin) {
|
||||||
const origin = window.location.origin;
|
const origin = window.location.origin;
|
||||||
@@ -32,7 +75,10 @@ export const createMusicSharePayload = ({ projectId, title, artist } = {}) => {
|
|||||||
|
|
||||||
const baseUrl = trimTrailingSlash(resolveBaseShareUrl());
|
const baseUrl = trimTrailingSlash(resolveBaseShareUrl());
|
||||||
if (!baseUrl) return null;
|
if (!baseUrl) return null;
|
||||||
const shareUrl = `${baseUrl}/music/${projectId}`;
|
const encodedProjectId = encodeURIComponent(projectId);
|
||||||
|
const sharePath = `music/${encodedProjectId}`;
|
||||||
|
const shareUrl = `${baseUrl}/${sharePath}`;
|
||||||
|
const schemeDeepLink = createSchemeDeepLink(sharePath);
|
||||||
|
|
||||||
let shareMessage = musiclandShareMessage;
|
let shareMessage = musiclandShareMessage;
|
||||||
if (title) {
|
if (title) {
|
||||||
@@ -49,7 +95,9 @@ export const createMusicSharePayload = ({ projectId, title, artist } = {}) => {
|
|||||||
shareMessage,
|
shareMessage,
|
||||||
url: shareUrl,
|
url: shareUrl,
|
||||||
qrUrl: shareUrl,
|
qrUrl: shareUrl,
|
||||||
|
copyUrl: shareUrl,
|
||||||
linkLabel: shareUrl,
|
linkLabel: shareUrl,
|
||||||
|
appLink: schemeDeepLink,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+16
-1
@@ -1,3 +1,18 @@
|
|||||||
{
|
{
|
||||||
"rewrites": [{ "source": "/tasks/:taskId", "destination": "/index.html" }]
|
"rewrites": [
|
||||||
|
{ "source": "/music/:musicId", "destination": "/index.html" },
|
||||||
|
{ "source": "/tasks/:taskId", "destination": "/index.html" },
|
||||||
|
{ "source": "/playback/:playbackId", "destination": "/index.html" }
|
||||||
|
],
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"source": "/.well-known/apple-app-site-association",
|
||||||
|
"headers": [
|
||||||
|
{
|
||||||
|
"key": "Content-Type",
|
||||||
|
"value": "application/json; charset=utf-8"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"applinks": {
|
||||||
|
"apps": [],
|
||||||
|
"details": [
|
||||||
|
{
|
||||||
|
"appID": "W2QZ9CTMYJ.com.omedis.musicland.ai",
|
||||||
|
"paths": [
|
||||||
|
"/music/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"webcredentials": {
|
||||||
|
"apps": [
|
||||||
|
"W2QZ9CTMYJ.com.omedis.musicland.ai"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="fr">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta
|
||||||
|
name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, user-scalable=no, viewport-fit=cover"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<meta name="description" content="MusicLand" />
|
||||||
|
<meta
|
||||||
|
name="keywords"
|
||||||
|
content="musicland, musique, IA, création musicale, minuit.agency"
|
||||||
|
/>
|
||||||
|
<meta name="author" content="minuit.agency" />
|
||||||
|
|
||||||
|
<title>MusicLand</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;900&display=swap");
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
#root {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
min-height: 100dvh;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
overflow: -moz-scrollbars-none;
|
||||||
|
scrollbar-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-basis: auto;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus,
|
||||||
|
textarea:focus,
|
||||||
|
select:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
height: calc(100% + env(safe-area-inset-top));
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
overflow-y: auto;
|
||||||
|
overscroll-behavior-y: none;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-ms-overflow-style: scrollbar;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<form
|
||||||
|
action=""
|
||||||
|
style="
|
||||||
|
background-color: #fff;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
font-size: 18px;
|
||||||
|
font-family: Helvetica, sans-serif;
|
||||||
|
line-height: 24px;
|
||||||
|
margin: 10%;
|
||||||
|
width: 80%;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
Oh non ! Il semble que JavaScript ne soit pas activé sur votre
|
||||||
|
navigateur.
|
||||||
|
</p>
|
||||||
|
<p style="margin: 20px 0">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
style="
|
||||||
|
background-color: #4630eb;
|
||||||
|
border-radius: 100px;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 6px 16px;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
Recharger
|
||||||
|
</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user