Skip to content

Commit

Permalink
Merge pull request #48 from rtCamp/feature/storage-access-api-demo
Browse files Browse the repository at this point in the history
Storage Access API demo
  • Loading branch information
fellyph authored Feb 14, 2024
2 parents 4a301d1 + 1189cc2 commit 8a22efb
Show file tree
Hide file tree
Showing 14 changed files with 211 additions and 41 deletions.
2 changes: 1 addition & 1 deletion app.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ app.use((req, res, next) => {
});

// Mount routes for different demo types
const demoTypes = ['chips', 'related-websites-sets', 'private-state-tokens', 'fedcm'];
const demoTypes = ['chips', 'related-websites-sets', 'private-state-tokens', 'fedcm', 'storage-access-api'];
demoTypes.forEach(demoType => {
const demoRoutes = require(`./src/demos/${demoType}/routes`);
app.use(`/${demoType}`, demoRoutes); // Mount the routes on a path specific to the demo type
Expand Down
6 changes: 5 additions & 1 deletion public/assets/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ document.addEventListener('DOMContentLoaded', function() {
if (isIframe) {
const mainHeader = document.querySelector('.main-header');
const mainFooter = document.querySelector('.main-footer');
const internalPageHeader = document.querySelector('.internal-page-header');
const themeContainer = document.getElementById('theme-container');

mainHeader?.remove();
mainFooter?.remove();
mainFooter?.remove();
internalPageHeader?.remove('hidden');
themeContainer?.classList.add('h-screen');
}
});
25 changes: 0 additions & 25 deletions public/assets/styles/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -667,14 +667,6 @@ video {
position: relative;
}

.right-8 {
right: 2rem;
}

.top-8 {
top: 2rem;
}

.z-50 {
z-index: 50;
}
Expand Down Expand Up @@ -861,24 +853,12 @@ video {
gap: 1.5rem;
}

.space-x-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.5rem * var(--tw-space-x-reverse));
margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse)));
}

.space-x-4 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(1rem * var(--tw-space-x-reverse));
margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse)));
}

.space-y-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
}

.space-y-4 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));
Expand Down Expand Up @@ -1005,11 +985,6 @@ video {
text-align: center;
}

.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}

.text-3xl {
font-size: 1.875rem;
line-height: 2.25rem;
Expand Down
3 changes: 0 additions & 3 deletions src/common/common-scenarios.ejs

This file was deleted.

3 changes: 2 additions & 1 deletion src/common/index.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
<%= renderCard('Personalization with localStorage', '🖼️', '/personalization-localstorage') %>
<%= renderCard('Single Sign-On', '🔐', '/single-sign-on') %>
<%= renderCard('Payment Gateway', '💳', '/payment-gateway') %>
<%= renderCard('CHIPS', '🍪', '/chips') %>
<%= renderCard('Legacy GSI', '🔐', '/gsi') %>
<%= renderCard('Facebook', '👍', '/social-media') %>
<%= renderCard('CHIPS', '🍪', '/chips') %>
<%= renderCard('Storage Access API', '🗃️', '/storage-access-api') %>
</div>
</div>

Expand Down
2 changes: 1 addition & 1 deletion src/common/internal-page/header.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
%>
<div class="container mx-auto pt-8 pb-20">
<% if (title && displayHeader) { %>
<header>
<header class="internal-page-header">
<h1 class="text-3xl font-bold my-8 text-center text-slate-800"><%= title %></h1>
</header>
<% } %>
Expand Down
5 changes: 5 additions & 0 deletions src/demos/storage-access-api/index.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<%- include(commonPath + '/header.ejs') %>
<%- include(commonPath + '/internal-page/header.ejs') %>
<iframe src="<%= protocol %>://<%= domainC %><% if (isPortPresent) { %>:<%= port %><% } %>/storage-access-api/theme-selection" class="border-8 rounded w-full h-96 overflow-hidden"></iframe>
<%- include(commonPath + '/internal-page/footer.ejs') %>
<%- include(commonPath + '/footer.ejs') %>
103 changes: 103 additions & 0 deletions src/demos/storage-access-api/personalization.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
document.addEventListener('DOMContentLoaded', () => {
const baseURL = '<%= protocol %>://<%= domainC %><% if (isPortPresent) { %>:<%= port %><% } %>/personalization';
const pageContainer = document.getElementById('theme-container');
const themeSwitcher = document.getElementById('dark-mode-switch');
const errorMessages = document.getElementById('status-message');
const loadButton = document.getElementById('load-button');
const toggleContainer = document.querySelector('.dark-mode-toggle');
const isIframe = window.self !== window.top;
const containerClass = isIframe ? 'h-screen flex items-center justify-center' : 'flex items-center justify-center';
let hasStorageAccess = false;

document.hasStorageAccess().then(result => {
hasStorageAccess = result;
if ( hasStorageAccess ) {
updateUserPreference();
}
})

async function updateUserPreference() {
console.log('hasStorageAccess', hasStorageAccess);
if ( hasStorageAccess ) {
fetchAndApplyTheme();
} else {
try {
await document.requestStorageAccess();
toggleContainer.classList.remove('hidden');
loadButton.classList.add('hidden');
fetchAndApplyTheme();
} catch (error) {
console.error('There has been a problem with your fetch operation:', error);
errorMessages.textContent = `Error: ${error}`;
}
}
}

function fetchAndApplyTheme() {
fetch(`${baseURL}/get-personalization`, {
method: 'GET',
credentials: 'include'
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
errorMessages.textContent = `Network response was not ok ${response.status} - ${response.statusText}`;
}
return response.json();
})
.then(data => {
const theme = data.theme;
pageContainer.className = `${containerClass} ${data.theme}`
console.log('theme', theme);
if (theme === 'dark') {
themeSwitcher.checked = true;
}
})
.catch(error => {
console.error('There has been a problem with your fetch operation:', error);
errorMessages.textContent = `Error: ${error.message}`;
});
}

function fetchSetPersonalization() {
fetch( `${baseURL}/set-personalization`, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ theme: themeSwitcher?.checked ? 'dark' : 'light' })
})
.then(response => response.json())
.then(data => {
pageContainer.className = `${containerClass} ${data.theme}`;
});
}

async function toggleTheme() {
hasStorageAccess = await document.hasStorageAccess();

if( hasStorageAccess ) {
fetchSetPersonalization();
} else {
try {
await document.requestStorageAccess();
if ( await document.hasStorageAccess() ) {
fetchSetPersonalization();
} else {
console.error('User denied storage access');
errorMessages.textContent = 'User denied storage access';
}
} catch (error) {
console.error('Error:', error);
errorMessages.textContent = `The request to storage access API was denied because the user never interacted with the top-level site context or the permission wasn't grant by the user`;
}
}
}

window.toggleTheme = toggleTheme;
if (isIframe && !hasStorageAccess) {
console.log('In iframe');
toggleContainer.classList.add('hidden');
loadButton.classList.remove('hidden');
loadButton.addEventListener('click', updateUserPreference);
}
});
49 changes: 49 additions & 0 deletions src/demos/storage-access-api/routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const express = require('express');
const path = require('path');
const router = express.Router();

router.get('/', (req, res) => {
const currentDomain = req.get('host');
const template = currentDomain === res.locals.domainC ? 'theme-selection' : 'index';
res.render(path.join(__dirname,template), {
title: 'Storage Access API'
});
});

router.get('/theme-selection', (req, res) => {
res.render(path.join(__dirname,'theme-selection'), {
title: 'Storage Access API'
});
});


router.get( '/get-personalization', ( req, res ) => {
const currentTheme = req.cookies.theme || 'light';
res.json( { theme: currentTheme });
});

router.post( '/set-personalization', ( req, res ) => {
const { theme } = req.body;

if (!theme) {
res.status(400).send({ message: 'Invalid request' });

}

res.cookie('theme', theme, {
domain: res.locals.domainC,
maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days
httpOnly: true,
sameSite: "none",
secure: true
});
res.status(200).send({ message: 'Success', theme : theme});
});

// Serve the personalization.js file to the site
router.get('/personalization.js', (req, res) => {
res.set('Content-Type', 'application/javascript');
res.render(path.join(__dirname,'personalization'));
});

module.exports = router;
22 changes: 22 additions & 0 deletions src/demos/storage-access-api/theme-selection.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<%- include(commonPath + '/header.ejs') %>
<div id="theme-container" class="flex items-center justify-center">
<%- include(commonPath + '/internal-page/header.ejs', {containerType: 'sm'}) %>
<div class="text-red-500 p-4 text-sm" id="status-message"></div>
<button id="load-button" class="hidden px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-700 transition duration-300" onclick="toggleTheme()">
Load user preferences
</button>
<div class="dark-mode-toggle">
<input type="checkbox" id="dark-mode-switch" onclick="toggleTheme()" />
<label for="dark-mode-switch">
<span class="bullet">
<svg xmlns="http://www.w3.org/2000/svg" class="sun" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41L5.99 4.58zm12.37 12.37a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0a.996.996 0 0 0 0-1.41l-1.06-1.06zm1.06-10.96a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06zM7.05 18.36a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" class="moon" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 3a9 9 0 1 0 9 9c0-.46-.04-.92-.1-1.36a5.389 5.389 0 0 1-4.4 2.26 5.403 5.403 0 0 1-3.14-9.8c-.44-.06-.9-.1-1.36-.1z"/></svg>
</span>
</label>
</div>
<%- include(commonPath + '/internal-page/footer.ejs') %>
</div>

<script src="<%= protocol %>://<%= domainC %><% if (isPortPresent) { %>:<%= port %><% } %>/storage-access-api/personalization.js"></script>

<%- include(commonPath + '/footer.ejs') %>
4 changes: 3 additions & 1 deletion src/scenarios/personalization-localstorage/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ const path = require('path');
const router = express.Router();

router.get('/', (req, res) => {
res.render(path.join(__dirname,'index'), {
const currentDomain = req.get('host');
const pageTemplate = currentDomain === res.locals.domainC ? 'theme-selection' : 'index';
res.render(path.join(__dirname, pageTemplate), {
title: 'Personalization with localStorage'
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<%- include(commonPath + '/header.ejs') %>
<div id="theme-container" class="h-screen flex items-center justify-center">
<%- include(commonPath + '/internal-page/header.ejs', {showHeader: false, containerType: 'sm'}) %>
<div id="theme-container" class="flex items-center justify-center">
<%- include(commonPath + '/internal-page/header.ejs', { containerType: 'sm'}) %>
<div class="dark-mode-toggle">
<input type="checkbox" id="dark-mode-switch" />
<label for="dark-mode-switch">
Expand All @@ -19,7 +19,7 @@
// Check for saved theme preference in localStorage
const currentTheme = localStorage.getItem('theme');
console.log(currentTheme)
if (currentTheme === 'dark') {
themeContainer.classList.add(currentTheme);
themeSwitcher.checked = true;
Expand Down
1 change: 1 addition & 0 deletions src/scenarios/personalization/index.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<div id="theme-container">
<%- include(commonPath + '/internal-page/header.ejs', {containerType: 'sm'}) %>
<div class="dark-mode-toggle">
<div class="text-red-500 p-4 text-sm" id="status-message"></div>
<input type="checkbox" id="dark-mode-switch" onclick="toggleTheme()" />
<label for="dark-mode-switch">
<span class="bullet">
Expand Down
21 changes: 16 additions & 5 deletions src/scenarios/personalization/personalization.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ document.addEventListener('DOMContentLoaded', () => {
const baseURL = '<%= protocol %>://<%= domainC %><% if (isPortPresent) { %>:<%= port %><% } %>/personalization';
const pageContainer = document.getElementById('theme-container');
const themeSwitcher = document.getElementById('dark-mode-switch');

const statusMessage = document.getElementById('status-message');

function updateUserPreference() {
fetch(`${baseURL}/get-personalization`, {
method: 'GET',
Expand All @@ -16,12 +17,14 @@ document.addEventListener('DOMContentLoaded', () => {
})
.then(data => {
const theme = data.theme;
console.log(data.theme)
pageContainer.className = theme;
themeSwitcher.checked = theme === 'dark';
if ( theme === 'dark' ) {
pageContainer.classList.add('dark');
themeSwitcher.checked = true;
}
})
.catch(error => {
console.error('There has been a problem with your fetch operation:', error);
statusMessage.textContent = `There was an error fetching your personalization settings: ${error.message}`;
});
}

Expand All @@ -32,9 +35,17 @@ document.addEventListener('DOMContentLoaded', () => {
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ theme: themeSwitcher?.checked ? 'dark' : 'light' })
})
.then(response => response.json())
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
pageContainer.className = data.theme;
}).catch(error => {
console.error('There has been a problem with your fetch operation:', error);
statusMessage.textContent = `There was an error updating your personalization settings: ${error.message}`;
});
}
window.toggleTheme = toggleTheme;
Expand Down

0 comments on commit 8a22efb

Please sign in to comment.