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
39 changes: 39 additions & 0 deletions build/public/css/stats.css

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions build/public/game.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<meta name="mobile-web-app-capable" content="yes">
<meta name="description" content="An online roguelike in your browser with a fresh dungeon generated each day.">
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/stats.css">
<link rel="icon" href="icon.png">
<!-- twitter social -->
<meta content="https://rogule.com/icon.png" name="twitter:image:src">
Expand All @@ -29,5 +30,6 @@
</main>
<script src="js/shared.js"></script>
<script src="js/main.js"></script>
<script src="js/stats.js"></script>
</body>
</html>
155 changes: 155 additions & 0 deletions build/public/js/stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
const stats = (function () {
const FILENAME = {
TEMPLATE: 'rogule-browser-backup-[date].json',
REPLACEABLE_ITEM: '[date]'
};
const LS_ITEM = `["~#'","~:game-state"]`;


function getFilename(TEMPLATE, REPLACEABLE_ITEM) {
return TEMPLATE.replace(REPLACEABLE_ITEM, getBackupDate())
}


function getBackupDate() {
const [month, day, year] = new Date().toLocaleDateString('en').split('/');
return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`;
}


function save(filename, data) {
if (data) {
const a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([data], { type: 'application/json' }));
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
}


function handleNewUpload(event) {
const VALID_TYPE = 'application/json';
const field = event.target;
const file = field.files[0];
if (file.type === VALID_TYPE) {
const reader = new FileReader();
reader.onload = (event) => {
handleFileLoad(event, field);
};
reader.readAsText(file)
} else {
field.value = null;
}
}


function saveStats(itemName, data) {
localStorage.setItem(itemName, data);
}

function disableBlock(el) {
console.log(el)
el.setAttribute('aria-hidden', 'true');
el.style.pointerEvents = 'none';
const links = el.querySelectorAll('a');
const buttons = el.querySelectorAll('button');
const items = [...links, ...buttons];
items.forEach(item => {
item.setAttribute('tabindex', -1);
item.classList.add('--tmp-disabled');
});
}

function enableBlock(el) {
el.setAttribute('aria-hidden', 'false');
el.style.pointerEvents = null;
const items = el.querySelectorAll('.--tmp-disabled');
items.forEach(item => {
item.removeAttribute('tabindex');
item.classList.remove('--tmp-disabled');
});
}

function closeWarning(modal, app) {
modal.classList.remove('warning-modal--visible');
modal.remove();
enableBlock(app);
}


function showWarning(data) {
const modalTemplate = `
<section class="warning-modal js__warning-modal">
<div class="warning-modal__panel">
<h2 class="warning-modal__title mage">Magic is a powerful, thus dangerous <sup><span class="warning-modal__asterisk">*</span></sup> ally.</h2>
<p class="warning-modal__subtitle">Do you really want to continue?</p>
<ul class="warning-modal__actions">
<li class="warning-modal__action">
<button class="key warning-modal__action-btn-continue js__warning-modal-btn-continue">YAS!</button>
</li>
<li class="warning-modal__action">
<button class="warning-modal__action-btn-cancel js__warning-modal-btn-cancel">Hell, no</button>
</li>
</ul>
<p class="warning-modal__note"><span class="warning-modal__asterisk">*</span> Maybe there is a previous save in this browser.</p>
</div>
</section>
`;
const game = document.querySelector('.game');
const app = game.querySelector('#app');
game.insertAdjacentHTML('beforeend', modalTemplate);
const modal = game.querySelector('.js__warning-modal');
const modalContinue = modal.querySelector('.js__warning-modal-btn-continue');
const modalCancel = modal.querySelector('.js__warning-modal-btn-cancel');
modal.classList.add('warning-modal--visible');
disableBlock(app);

modalContinue && modalContinue.addEventListener('click', () => {
localStorage.setItem(LS_ITEM, JSON.stringify(data));
closeWarning(modal, app);
});
modalCancel && modalCancel.addEventListener('click', () => {
closeWarning(modal, app);
});
}


function handleFileLoad(event, field) {
const contents = JSON.parse(event.target.result);

if (typeof contents === 'object' && contents.length) {
showWarning(contents);
}
field.value = null;

}


function init(wrapper) {
const backupBtn = wrapper.querySelector('.js__stats-action-backup');
const importBtn = wrapper.querySelector('.js__stats-action-import');
const uploadBtn = wrapper.querySelector('.js__app-upload-stats');
backupBtn.addEventListener('click', () => {
const { TEMPLATE, REPLACEABLE_ITEM } = FILENAME;
const filename = getFilename(TEMPLATE, REPLACEABLE_ITEM);
const myStats = localStorage.getItem(LS_ITEM);
save(filename, myStats);
});
importBtn.addEventListener('click', () => {
uploadBtn.click();
});
uploadBtn.addEventListener('change', handleNewUpload);
}

return {
init,
};
})();

window.addEventListener('load', () => {
const statsBlock = document.querySelector('.js__stats');
statsBlock && stats.init(statsBlock);
});

144 changes: 144 additions & 0 deletions public/css/stats.css

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions public/game.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<meta name="mobile-web-app-capable" content="yes">
<meta name="description" content="An online roguelike in your browser with a fresh dungeon generated each day.">
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/stats.css">
<link rel="icon" href="icon.png">
<!-- twitter social -->
<meta content="https://rogule.com/icon.png" name="twitter:image:src">
Expand All @@ -29,5 +30,6 @@
</main>
<script src="js/shared.js"></script>
<script src="js/main.js"></script>
<script src="js/stats.js"></script>
</body>
</html>
1 change: 1 addition & 0 deletions shadow-cljs.edn
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
:main rogule.server/main!
:release {:output-to "build/server.js"}}
:app {:target :browser
:build-hooks [(shadow.html/copy-file "build/public/js/stats.js" "public/js/stats.js")]
:output-dir "public/js"
:asset-path "/js"
:modules {:shared {:entries []}
Expand Down
7 changes: 6 additions & 1 deletion src/rogule/ui.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,12 @@
[:a {:href "https://ko-fi.com/chr15m" :target "_blank"}
[:span {:ref (fn [el] (when el (aset el "innerHTML" (rc/inline "ko-fi.svg"))))}]]
(emoj (load-sprite :folded-hands))]
[:p [:a {:href "mailto:chris@rogule.com"} "Send feedback"]]]))
[:p [:a {:href "mailto:chris@rogule.com"} "Send feedback"]]
[:div.js__stats
[:ul.stats
[:li.stats__item [:button.key.stats__action.stats__action--backup.js__stats-action-backup [:span.stats__action-label "Backup stats"]]]
[:li.stats__item [:button.key.stats__action.stats__action--import.js__stats-action-import [:span.stats__action-label "Import stats"]]]]
[:input {:class "hidden js__app-upload-stats" :type "file" :name "upload-file" :id "upload-file" :tabIndex "-1" :aria-hidden "true"}]]]))

(defn component-main [state]
(if (:outcome @state)
Expand Down