Mattias Bodlund 1 year ago
parent
commit
1e0ff4782e
5 changed files with 131 additions and 77 deletions
  1. +11
    -0
      app/assets/stylesheets/application.css
  2. +3
    -3
      app/helpers/site_helper.rb
  3. +114
    -71
      app/javascript/application.js
  4. +1
    -1
      app/views/site/tmpl_article.html.erb
  5. +2
    -2
      app/views/site/tmpl_index.html.erb

+ 11
- 0
app/assets/stylesheets/application.css View File

@ -112,6 +112,17 @@ ul[class] {
list-style: none; list-style: none;
} }
img.fade-in {
opacity: 0;
transition: opacity 0.4s ease-in;
&.loaded {
opacity: 1;
}
}
header { header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;


+ 3
- 3
app/helpers/site_helper.rb View File

@ -1,7 +1,7 @@
module SiteHelper module SiteHelper
def frontend_javascript_importmap_tags def frontend_javascript_importmap_tags
only_use = %w"application"
only_use = %w"application @hotwired/turbo-rails"
importmap_json = JSON.parse(Rails.application.importmap.to_json(resolver: self))['imports'].select{ |k,v| only_use.include?(k)} importmap_json = JSON.parse(Rails.application.importmap.to_json(resolver: self))['imports'].select{ |k,v| only_use.include?(k)}
safe_join [ safe_join [
javascript_inline_importmap_tag(JSON.pretty_generate({ "imports" => importmap_json})), javascript_inline_importmap_tag(JSON.pretty_generate({ "imports" => importmap_json})),
@ -35,8 +35,8 @@ module SiteHelper
first_link = doc.at_css('a') first_link = doc.at_css('a')
first_link.remove if first_link first_link.remove if first_link
result[:title] = doc.at_css('h1').text
result[:description] = doc.at_css('div').text
result[:title] = doc.at_css('h1')&.text
result[:description] = doc.at_css('div')&.text
result[:link] = first_link&.to_html result[:link] = first_link&.to_html
doc.search('*').each do |node| doc.search('*').each do |node|


+ 114
- 71
app/javascript/application.js View File

@ -1,3 +1,14 @@
import "@hotwired/turbo-rails"
var input_range
const max_value = 180
const speed = 12
var curr_value
var raf_id
var random_salt = Math.random()
function rand_in_range(from, to) { function rand_in_range(from, to) {
const rand = Math.floor(Math.random() * (to - from + 1)) + from const rand = Math.floor(Math.random() * (to - from + 1)) + from
@ -36,91 +47,141 @@ function shuffle_cards() {
localStorage.setItem('shown_cards', JSON.stringify(shown_cards)); localStorage.setItem('shown_cards', JSON.stringify(shown_cards));
} }
document.querySelectorAll('.button_shuffle_cards').forEach((item, index) => {
item.addEventListener('click', (e) => {
shuffle_cards()
})
if (index == 0)
shuffle_cards()
document.addEventListener("turbo:load", ()=> {
init()
}) })
document.addEventListener("turbo:before-cache", () => {
if (input_range) {
input_range.value = 0;
input_range.closest('.reveal__container').style.setProperty('--opacity', 1);
updateRotation(input_range.value)
}
// Choose language confirmation button
document.querySelectorAll('#confirm_btn').forEach((confirm_btn) => {
confirm_btn.addEventListener('click', (e) => {
window.location.href = '/' + document.getElementById('language_select').value
let images = document.querySelectorAll("img.fade-in.loaded")
images.forEach(image => {
image.classList.remove("loaded")
}) })
}) })
// Copy link to clipboard
document.querySelectorAll('[data-share-title]').forEach((share_btn) => {
share_btn.addEventListener('click', (e) => {
if (navigator.share) {
navigator.share({
title: e.currentTarget.getAttribute('data-share-title'),
text: e.currentTarget.getAttribute('data-share-text'),
url: window.location.href
}).then(() => {
console.log('Thanks for sharing!');
})
.catch(console.error);
} else {
navigator.clipboard.writeText(window.location.href)
alert('URL copied to clipboard!')
}
function init() {
random_salt = Math.random()
document.querySelectorAll('.button_shuffle_cards').forEach((item, index) => {
item.addEventListener('click', (e) => {
shuffle_cards()
})
if (index == 0)
shuffle_cards()
}) })
})
document.querySelectorAll('.card__stack a').forEach((card_link) => {
card_link.addEventListener('click', (e) => {
e.preventDefault()
// Choose language confirmation button
document.querySelectorAll('#confirm_btn').forEach((confirm_btn) => {
confirm_btn.addEventListener('click', (e) => {
// window.location.href = '/' + document.getElementById('language_select').value
Turbo.visit('/' + document.getElementById('language_select').value, {advance: 'advance'})
})
}) })
})
// Open all external links in ny tab
for (const link of document.links) {
if (link.hostname.replace(/^www\./i, "") != window.location.hostname.replace(/^www\./i, "") && (link.protocol == 'https:' || link.protocol == 'http:'))
link.target = '_blank'
}
// Copy link to clipboard
document.querySelectorAll('[data-share-title]').forEach((share_btn) => {
share_btn.addEventListener('click', (e) => {
if (navigator.share) {
navigator.share({
title: e.currentTarget.getAttribute('data-share-title'),
text: e.currentTarget.getAttribute('data-share-text'),
url: window.location.href
}).then(() => {
console.log('Thanks for sharing!');
})
.catch(console.error);
} else {
navigator.clipboard.writeText(window.location.href)
alert('URL copied to clipboard!')
}
})
})
document.querySelectorAll('.card__stack a').forEach((card_link) => {
card_link.addEventListener('click', (e) => {
e.preventDefault()
})
})
// Open all external links in ny tab
for (const link of document.links) {
if (link.hostname.replace(/^www\./i, "") != window.location.hostname.replace(/^www\./i, "") && (link.protocol == 'https:' || link.protocol == 'http:'))
link.target = '_blank'
}
input_range = document.getElementsByClassName('reveal')[0]
const input_range = document.getElementsByClassName('reveal')[0]
const max_value = 180
const speed = 12
if (input_range) {
input_range.min = 0;
input_range.max = max_value;
}
var curr_value
var raf_id
if (input_range) {
input_range.addEventListener('mousedown', unlockStartHandler, false)
input_range.addEventListener('touchstart', unlockStartHandler, false)
input_range.addEventListener('mouseup', unlockEndHandler, false)
input_range.addEventListener('touchend', unlockEndHandler, false)
input_range.addEventListener("input", (e) => {
e.currentTarget.closest('.reveal__container').style.setProperty('--opacity', 1 - (e.currentTarget.value/e.currentTarget.max))
updateRotation(e.currentTarget.value)
})
}
let images = document.querySelectorAll("img.fade-in")
images.forEach(image => {
image.addEventListener("load", () => {
image.classList.add("loaded")
})
if (input_range) {
input_range.min = 0;
input_range.max = max_value;
// For cached images that may already be loaded
if (image.complete) {
window.requestAnimationFrame(() => {
image.classList.add("loaded")
})
}
})
} }
function unlockStartHandler() { function unlockStartHandler() {
window.cancelAnimationFrame(raf_id); window.cancelAnimationFrame(raf_id);
curr_value = +this.value; curr_value = +this.value;
} }
function unlockEndHandler() { function unlockEndHandler() {
curr_value = +this.value; curr_value = +this.value;
if (curr_value >= this.max) { if (curr_value >= this.max) {
const card = document.querySelector('.card__container.active') const card = document.querySelector('.card__container.active')
window.location.href = card.parentNode.getAttribute('href')
//window.location.href = card.parentNode.getAttribute('href')
Turbo.visit(card.parentNode.getAttribute('href'), { action: 'advance'} )
// reset
this.value = 0;
this.closest('.reveal__container').style.setProperty('--opacity', 1);
} else { } else {
raf_id = window.requestAnimationFrame(animateHandler); raf_id = window.requestAnimationFrame(animateHandler);
} }
} }
// handle range animation // handle range animation
function animateHandler() { function animateHandler() {
@ -137,39 +198,21 @@ function animateHandler() {
curr_value = curr_value - speed; curr_value = curr_value - speed;
} }
if (input_range) {
input_range.addEventListener('mousedown', unlockStartHandler, false)
input_range.addEventListener('mousestart', unlockStartHandler, false)
input_range.addEventListener('mouseup', unlockEndHandler, false)
input_range.addEventListener('touchend', unlockEndHandler, false)
input_range.addEventListener("input", (e) => {
e.currentTarget.closest('.reveal__container').style.setProperty('--opacity', 1 - (e.currentTarget.value/e.currentTarget.max))
updateRotation(e.currentTarget.value)
})
}
function updateRotation(angle) { function updateRotation(angle) {
document.documentElement.style.setProperty('--flip-deg', angle + 'deg')
document.documentElement.style.setProperty('--flip-scale', calculateScaleFactor(angle))
document.documentElement.style.setProperty('--flip-rotate', calculateRotateFactor(angle) + 'deg')
document.documentElement.style.setProperty('--flip-deg', angle + 'deg')
document.documentElement.style.setProperty('--flip-scale', calculateScaleFactor(angle))
document.documentElement.style.setProperty('--flip-rotate', calculateRotateFactor(angle) + 'deg')
} }
const random_salt = Math.random()
function calculateScaleFactor(angle) { function calculateScaleFactor(angle) {
const radians = angle * (Math.PI / 180) const radians = angle * (Math.PI / 180)
return 1 + (0.1 * Math.sin(radians)) return 1 + (0.1 * Math.sin(radians))
// return 1 + (0.2 * (angle / 180)) // return 1 + (0.2 * (angle / 180))
} }
function calculateRotateFactor(angle) { function calculateRotateFactor(angle) {
const radians = angle * (Math.PI / 180) const radians = angle * (Math.PI / 180)
return (4 * Math.sin(radians)) + (random_salt * 2) return (4 * Math.sin(radians)) + (random_salt * 2)


+ 1
- 1
app/views/site/tmpl_article.html.erb View File

@ -25,7 +25,7 @@
#{rails_storage_proxy_url(asset.file.variant(resize_to_fill: [1002,1369]))} 1002w #{rails_storage_proxy_url(asset.file.variant(resize_to_fill: [1002,1369]))} 1002w
", ",
sizes: "", sizes: "",
loading: 'lazy' if asset&.file&.image? %>
class: 'fade-in' if asset&.file&.image? %>
<% end %> <% end %>
<div class="link__body-container"> <div class="link__body-container">


+ 2
- 2
app/views/site/tmpl_index.html.erb View File

@ -19,7 +19,7 @@
srcset: " srcset: "
#{rails_storage_proxy_url(asset.file.variant(resize_to_limit: [320,320]))} 2x, #{rails_storage_proxy_url(asset.file.variant(resize_to_limit: [320,320]))} 2x,
#{rails_storage_proxy_url(asset.file.variant(resize_to_limit: [640,640]))} 3x #{rails_storage_proxy_url(asset.file.variant(resize_to_limit: [640,640]))} 3x
",
loading: 'lazy' if asset&.file&.image? %>
",
class: 'fade-in' if asset&.file&.image? %>
<% end %> <% end %>
</div> </div>

Loading…
Cancel
Save