Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 89 additions & 1 deletion _sass/blocks/joinzone.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,92 @@
.download-prompt {
margin-top: 30px;
}
}

.joinzone__actions {
display: flex;
gap: 12px;
justify-content: center;
align-items: center;
flex-wrap: wrap;
margin-top: 14px;
}

.joinzone__status {
margin-top: 16px;
color: #54595e;
}

.joinzone__fallback {
margin-top: 18px;
max-width: 720px;
margin-left: auto;
margin-right: auto;
}
}

.joinzone-openapp-modal {
position: fixed;
inset: 0;
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}

.joinzone-openapp-modal[hidden] {
display: none;
}

.joinzone-openapp-modal__backdrop {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.55);
}

.joinzone-openapp-modal__dialog {
position: relative;
width: 100%;
max-width: 560px;
background: #ffffff;
border-radius: 14px;
padding: 24px 22px;
box-shadow: 0 18px 60px rgba(0, 0, 0, 0.3);
}

.joinzone-openapp-modal__title {
margin-top: 0;
margin-bottom: 8px;
color: #2d3e50;
}

.joinzone-openapp-modal__text {
margin-top: 0;
color: #54595e;
}

.joinzone-openapp-modal__actions {
display: flex;
gap: 12px;
flex-wrap: wrap;
margin-top: 16px;
}

.joinzone-openapp-modal__note {
margin-top: 14px;
margin-bottom: 0;
color: #54595e;
font-size: 14px;
}

.joinzone-openapp-modal__close {
position: absolute;
top: 10px;
right: 12px;
border: 0;
background: transparent;
font-size: 28px;
line-height: 1;
cursor: pointer;
color: #2d3e50;
}
210 changes: 167 additions & 43 deletions joinzone.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,66 +9,190 @@
---

<script>
var url = new URL(document.location.toString());
let code = url.hash.slice(1)
if (code.length < 32) {
window.location.replace((url.origin + url.pathname).replace("/joinzone/", "/"));
} else {
// After 2 seconds, open the invite link
// Not enabled for now
// setTimeout(function() { window.location.href = "ddrive://invite/" + code }, 2000);
}
(function () {
const url = new URL(window.location.href);
const codePattern = /^[A-Za-z0-9_-]{32,}$/;

// Helper function to strip leading/trailing spaces from text
function stripSpaces(str) {
return str.replace(/^\s+|\s+$/g, '');
}
const hashValue = (url.hash || "").replace(/^#/, "").trim();
const queryValue = (url.searchParams.get("invite") || url.searchParams.get("code") || "").trim();

const looksLikeCode = (value) => codePattern.test(value);
const inviteCode = looksLikeCode(queryValue) ? queryValue : (looksLikeCode(hashValue) ? hashValue : "");

function CopyToClipboard(id)
{
if (!inviteCode) {
window.location.replace((url.origin + url.pathname).replace(/\/joinzone\/?$/, "/"));
return;
}

// Backwards compatibility: turn /joinzone/#<code> into /joinzone/?invite=<code>
// so the hash remains available for popups like #download-app.
if (!looksLikeCode(queryValue) && looksLikeCode(hashValue)) {
url.hash = "";
url.searchParams.set("invite", inviteCode);
history.replaceState({}, "", url.toString());
}

window.__joinzoneInviteCode = inviteCode;
})();

function CopyToClipboard(id) {
var el = document.getElementById(id);
// Get the text content and strip leading/trailing spaces
var text = stripSpaces(el.textContent || el.innerText || "");
// Create a temporary textarea to copy the stripped text
// If the element contains a <script>, extract only the code variable
if (el.querySelector && el.querySelector('script')) {
text = code;
var text = (el && (el.textContent || el.innerText) || "").trim();

function showNotification() {
document.querySelector("#notify").style.display = "";
setTimeout(function () {
document.querySelector("#notify").style.display = "none";
}, 3000);
}

function legacyCopy(value) {
var tempInput = document.createElement("textarea");
tempInput.value = value;
tempInput.setAttribute("readonly", "");
tempInput.style.position = "fixed";
tempInput.style.top = "0";
tempInput.style.left = "0";
tempInput.style.opacity = "0";
document.body.appendChild(tempInput);
tempInput.select();
try {
document.execCommand("copy");
showNotification();
} catch (err) {
console.error("Could not copy text: ", err);
}
document.body.removeChild(tempInput);
}

if (!text) return;

if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(text).then(showNotification, function (err) {
console.error("Could not copy text: ", err);
legacyCopy(text);
});
} else {
legacyCopy(text);
}
var tempInput = document.createElement("textarea");
tempInput.value = text;
document.body.appendChild(tempInput);
tempInput.select();
document.execCommand('copy');
document.body.removeChild(tempInput);

document.querySelector("#notify").style.display = "";
setTimeout(function(){
document.querySelector("#notify").style.display = "none";
}, 3000);
}

</script>

<script>
document.addEventListener("DOMContentLoaded", function () {
const getInviteCode = () => window.__joinzoneInviteCode || "";

const inviteCode = getInviteCode();
if (!inviteCode) return;

const deepLink = "ddrive://invite/" + inviteCode;
const joinCodeEl = document.getElementById("joincode");
if (joinCodeEl) joinCodeEl.textContent = inviteCode;

const isAndroid = /Android/i.test(navigator.userAgent);
const isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);
const isMobile = isAndroid || isIOS;

const cfgEl = document.getElementById("joinzone-config");
const iosStoreUrl = (cfgEl && cfgEl.dataset && cfgEl.dataset.iosStoreUrl) || "";
const androidStoreUrl = (cfgEl && cfgEl.dataset && cfgEl.dataset.androidStoreUrl) || "";
const downloadCenterUrl = (cfgEl && cfgEl.dataset && cfgEl.dataset.downloadCenterUrl) || "/download/";
const downloadUrl = isIOS ? iosStoreUrl : (isAndroid ? androidStoreUrl : downloadCenterUrl);

document.querySelectorAll("[data-joinzone-download]").forEach((link) => {
link.setAttribute("href", downloadUrl || downloadCenterUrl);
});

const desktopModal = document.getElementById("joinzone-openapp-modal");
const mobileStatus = document.getElementById("joinzone-mobile-status");
const fallback = document.getElementById("joinzone-fallback");

function attemptOpenApp(url) {
try {
window.location.href = url;
} catch (e) {}

// If the app didn't open (blocked, not installed, or user canceled), reveal a fallback CTA.
setTimeout(function () {
if (fallback) fallback.hidden = false;
}, 1500);
}

document.querySelectorAll("[data-joinzone-openinapp]").forEach((link) => {
link.setAttribute("href", deepLink);
link.addEventListener("click", function (e) {
e.preventDefault();
attemptOpenApp(deepLink);
});
});

document.querySelectorAll("[data-joinzone-close]").forEach((button) => {
button.addEventListener("click", function () {
if (desktopModal) desktopModal.hidden = true;
});
});

if (isMobile) {
if (mobileStatus) mobileStatus.hidden = false;
attemptOpenApp(deepLink);
} else {
if (desktopModal) desktopModal.hidden = false;
}
});
</script>

<div
id="joinzone-config"
hidden
data-ios-store-url="{{ site.download.app.ios }}"
data-android-store-url="{{ site.download.app.android }}"
data-download-center-url="{{ site.links.download.url | relative_url }}"
></div>

<div class="joinzone-openapp-modal" id="joinzone-openapp-modal" hidden>
<div class="joinzone-openapp-modal__backdrop" data-joinzone-close></div>
<div class="joinzone-openapp-modal__dialog" role="dialog" aria-modal="true" aria-labelledby="joinzone-openapp-title">
<button type="button" class="joinzone-openapp-modal__close" data-joinzone-close aria-label="Close">×</button>
<h3 class="joinzone-openapp-modal__title" id="joinzone-openapp-title">Open in Diode</h3>
<p class="joinzone-openapp-modal__text">Click below to open the Diode app and join this Zone.</p>
<div class="joinzone-openapp-modal__actions">
<a class="btn" href="#" role="button" data-joinzone-openinapp>Open in App</a>
<a class="btn btn--blank" href="#close" data-joinzone-close>Continue on Web</a>
</div>
<p class="joinzone-openapp-modal__note">No app? <a href="#download-app" class="popup-open" data-joinzone-close>Download Diode</a></p>
</div>
</div>

<div class="text-center joinzone">
<h2 class="title">Join Code</h2>
<hr class="title_line">
<p class="subtitle">Click the "Join" button on the Zones page in Diode and enter this Join Code!</p>
<h3 type="text" class="joincode" id="joincode">
<script>
document.write(code)
</script>
</h3>
<button onclick="CopyToClipboard('joincode')" class="btn popup-open" id="cc-copy">
Copy to Clipboard
</button>

<h3 class="joincode" id="joincode"></h3>

<div class="joinzone__actions">
<a class="btn" href="#" role="button" data-joinzone-openinapp>Open in App</a>
<button onclick="CopyToClipboard('joincode')" class="btn" id="cc-copy">Copy to Clipboard</button>
</div>

<div class="download-prompt" id="notify" role="alert" style="display: none;">
Copied!
</div>

<div class="joinzone__status" id="joinzone-mobile-status" hidden>
Opening Diode…
</div>

<div class="joinzone__fallback" id="joinzone-fallback" hidden>
<p>If Diode didn’t open, you can use the Join Code above or download the app.</p>
<a class="btn" href="{{ site.links.download.url | relative_url }}" data-joinzone-download>Get Diode</a>
</div>

<br/><br/>
<img style="display:block; margin-left:auto; margin-right: auto; width: 520px;" src="{{ "joinzone/joincode-entry-example.gif" | prepend: site.path.images | relative_url}}" alt="how to join zone with join code">
<img style="display:block; margin-left:auto; margin-right: auto; width: 520px;" src="{{ 'joinzone/joincode-entry-example.gif' | prepend: site.path.images | relative_url}}" alt="how to join zone with join code">
<p class="download-prompt">Need Diode?</p>
<div>
<a href="#download-app" class="btn popup-open" target="">{{ site.links.download.title }}</a>
<a href="#download-app" class="btn popup-open">{{ site.links.download.title }}</a>
</div>
</div>