単語帳

問題

入力

設定

const closest = function(target, selector){
	if (!(target instanceof Element)) {
		target = target.parentElement;
	}
	if (!(target instanceof Element)) {
		return null;
	}
	return target.closest(selector);
};
const $ = function(selector, scope = document){
	return scope.querySelector(selector);
};
const $$ = function(selector, scope = document){
	return Array.from(scope.querySelectorAll(selector));
};
$$('.js-num').forEach(function(input){
	input.addEventListener('focus', function(){
		input.setAttribute('inputmode', 'tel');
	});
});
$$('input').forEach(function(input){
	input.addEventListener('keydown', function(e){
		if (e.key === 'Enter') {
			e.preventDefault();
		}
	});
});
function validation(target){
	const formLists = closest(target, 'ul.form_lists');
	if (!formLists) {
		return;
	}
	const btn = $('.js-btn', formLists);
	let isValid = true;
	$$('.js-must', formLists).forEach(function(item){
		if (!isValid) {
			return;
		}
		if (item.classList.contains('js-radio')) {
			const name = item.getAttribute('name');
			if (!$('input[name="' + name + '"]:checked', formLists)) {
				isValid = false;
			}
		} else if (item.classList.contains('js-check')) {
			if (!item.checked) {
				isValid = false;
			}
		} else if (item.classList.contains('js-text')) {
			if (item.value.trim() === '') {
				isValid = false;
			}
		}
	});
	if (btn) {
		btn.classList.toggle('peni', !isValid);
		btn.disabled = !isValid;
	}
}
$$('.js-form').forEach(function(item){
	['change', 'keyup', 'input'].forEach(function(eventName){
		item.addEventListener(eventName, function(){
			validation(item);
		});
	});
});
$$('ul.form_lists').forEach(function(formLists){
	const firstFormItem = $('.js-form', formLists);
	if (firstFormItem) {
		validation(firstFormItem);
	}
});
function scrollAction(){
	const winH = window.innerHeight;
	const actLine = winH * 7 / 8;
	const doneLine = winH * 1 / 8;
	$$('.js-scroll').forEach(function(item){
		const top = item.getBoundingClientRect().top;
		item.classList.toggle('act', top < actLine);
		item.classList.toggle('done', top < doneLine);
	});
}
function resetCardBg(){
	$$('.card_bg').forEach(function(bg){
		gsap.set(bg, {
			clearProps: 'transform,boxShadow'
		});
	});
}
const categoryMap = {
	strategy: 0,
	management: 1,
	technology: 2
};
const categoryKeys = Object.keys(categoryMap);
let categorySwiper = null;
if ($('.js-category-swiper')) {
	categorySwiper = new Swiper('.js-category-swiper', {
		speed: 400,
		autoHeight: true,
		allowTouchMove: false,
	});
	window.categorySwiper = categorySwiper;
}
function updateSwiper(){
	if (categorySwiper) {
		categorySwiper.update();
		categorySwiper.updateAutoHeight(0);
	}
	scrollAction();
}
window.addEventListener('scroll', scrollAction);
window.addEventListener('resize', function(){
	resetCardBg();
	updateSwiper();
});
scrollAction();
document.addEventListener('change', function(e){
	const input = closest(e.target, 'input[name="category"]');
	if (!input) {
		return;
	}
	const category = input.value;
	if (categorySwiper && categoryMap[category] !== undefined) {
		categorySwiper.slideTo(categoryMap[category]);
		setTimeout(function(){
			updateSwiper();
		}, 0);
	}
});
if (categorySwiper) {
	categorySwiper.on('slideChange', function(){
		const activeIndex = categorySwiper.activeIndex;
		const category = categoryKeys.find(function(key){
			return categoryMap[key] === activeIndex;
		});
		if (category) {
			const input = $('input[name="category"][value="' + category + '"]');
			if (input) {
				input.checked = true;
			}
		}
	});
}
if (window.matchMedia('(hover: hover) and (pointer: fine)').matches) {
	document.addEventListener('mousemove', function(e){
		const card = closest(e.target, '.card');
		if (!card || !card.classList.contains('act')) {
			return;
		}
		const bg = $('.card_bg', card);
		if (!bg) {
			return;
		}
		const rect = card.getBoundingClientRect();
		const x = e.clientX - rect.left;
		const y = e.clientY - rect.top;
		const centerX = rect.width / 2;
		const centerY = rect.height / 2;
		const rotateY = ((x - centerX) / centerX) * 8;
		const rotateX = ((centerY - y) / centerY) * 8;
		gsap.to(bg, {
			rotateX: rotateX,
			rotateY: rotateY,
			z: 12,
			scale: 1.02,
			boxShadow: '0 16px 32px 0 hsla(222, 22%, 4%, .4)',
			duration: .32,
			ease: 'power3.out',
			overwrite: true
		});
	});
	document.addEventListener('mouseleave', function(e){
		const card = closest(e.target, '.card');
		if (!card) {
			return;
		}
		const bg = $('.card_bg', card);
		if (!bg) {
			return;
		}
		gsap.to(bg, {
			rotateX: 0,
			rotateY: 0,
			z: 0,
			scale: 1,
			boxShadow: '0 0 0 0 hsla(222, 22%, 4%, 0)',
			duration: .8,
			ease: 'elastic.out(1, .45)'
		});
	}, true);
}
function filterWords(){
	const favoriteInput = $('.js-filter-favorite');
	const displayInput = $('.js-filter-display');
	const searchInput = $('.js-search-word');
	const favoriteOnly = favoriteInput ? favoriteInput.checked : false;
	const displayOnly = displayInput ? displayInput.checked : false;
	const keyword = searchInput ? searchInput.value.trim().toLowerCase() : '';
	$$('.js-word').forEach(function(word){
		const favorite = word.getAttribute('data-favorite');
		const display = word.getAttribute('data-display');
		const searchText = (word.getAttribute('data-search') || '').toLowerCase();
		let show = true;
		if (favoriteOnly && favorite !== 'on') {
			show = false;
		}
		if (displayOnly && display !== 'on') {
			show = false;
		}
		if (keyword && !searchText.includes(keyword)) {
			show = false;
		}
		word.style.display = show ? '' : 'none';
	});
	updateSwiper();
}
document.addEventListener('change', function(e){
	if (
		closest(e.target, '.js-filter-favorite') ||
		closest(e.target, '.js-filter-display')
	) {
		filterWords();
	}
});
document.addEventListener('input', function(e){
	if (closest(e.target, '.js-search-word')) {
		filterWords();
	}
});
document.addEventListener('change', function(e){
	const checkbox = closest(e.target, '.js-favorite, .js-display');
	if (!checkbox) {
		return;
	}
	const card = closest(checkbox, '.js-word');
	if (!card) {
		return;
	}
	const field = checkbox.classList.contains('js-favorite') ? 'favorite' : 'display';
	const value = checkbox.checked ? 'on' : 'off';
	const formData = new FormData();
	formData.append('action', 'vocab_update_word');
	formData.append('post_id', card.getAttribute('data-id'));
	formData.append('field', field);
	formData.append('value', value);
	fetch(vocab.ajax_url, {
		method: 'POST',
		body: formData,
		credentials: 'same-origin'
	})
	.then(function(response){
		return response.json();
	})
	.then(function(res){
		if (res.success) {
			card.setAttribute('data-' + field, value);
			filterWords();
		}
	});
});
function sortWords(section){
	const list = $('.js-word-list', section);
	if (!list) {
		return;
	}
	const checkedSort = $('input[type="radio"][name^="sort_"]:checked', section);
	const sort = checkedSort ? checkedSort.value : 'new';
	const words = $$('.js-word', list);
	words.sort(function(a, b){
		const dateA = Number(a.getAttribute('data-date'));
		const dateB = Number(b.getAttribute('data-date'));
		if (sort === 'old') {
			return dateA - dateB;
		}
		if (sort === 'random') {
			return Math.random() - 0.5;
		}
		return dateB - dateA;
	});
	words.forEach(function(word){
		list.appendChild(word);
	});
	updateSwiper();
}
document.addEventListener('change', function(e){
	const input = closest(e.target, 'input[type="radio"][name^="sort_"]');
	if (!input) {
		return;
	}
	const section = closest(input, 'section.cards');
	if (section) {
		sortWords(section);
	}
});
document.addEventListener('change', function(e){
	const radio = closest(e.target, '.js-format');
	if (!radio) {
		return;
	}
	const formData = new FormData();
	formData.append('action', 'vocab_update_setting');
	formData.append('post_id', radio.getAttribute('data-post-id'));
	formData.append('field', 'format');
	formData.append('value', radio.value);
	fetch(vocab.ajax_url, {
		method: 'POST',
		body: formData,
		credentials: 'same-origin'
	});
});
function initLogoAnimation(){
	const logo = $('header .logo a');
	const parts = $$('header .logo svg polygon, header .logo svg path');
	if (!logo || !parts.length) {
		return;
	}
	gsap.set(parts, {
		transformOrigin: '50% 50%',
		transformBox: 'fill-box',
		fill: 'var(--white)',
		opacity: 1
	});
	const bounceTl = gsap.timeline({
		repeat: -1,
		repeatDelay: 1.2
	});
	parts.forEach(function(part, index){
		bounceTl.to(part, {
			y: -5,
			scaleX: 0.94,
			scaleY: 1.1,
			rotation: index % 2 === 0 ? -3 : 3,
			duration: 0.32,
			ease: 'power2.out'
		}, index * 0.16);
		bounceTl.to(part, {
			y: 2,
			scaleX: 1.08,
			scaleY: 0.92,
			rotation: 0,
			duration: 0.28,
			ease: 'power2.inOut'
		}, index * 0.16 + 0.32);
		bounceTl.to(part, {
			y: 0,
			scaleX: 1,
			scaleY: 1,
			rotation: 0,
			duration: 0.7,
			ease: 'elastic.out(1, .45)'
		}, index * 0.16 + 0.6);
	});
	gsap.to(parts, {
		fill: 'var(--lightblue)',
		duration: 2,
		stagger: {
			each: 0.12,
			yoyo: true,
			repeat: -1
		},
		ease: 'sine.inOut'
	});
	gsap.to(parts, {
		fill: 'var(--lightpurple)',
		duration: 2,
		stagger: {
			each: 0.12,
			from: 'end',
			yoyo: true,
			repeat: -1
		},
		ease: 'sine.inOut',
		delay: 2
	});
	logo.addEventListener('mouseenter', function(){
		gsap.to(parts, {
			y: -4,
			scale: 1.04,
			duration: 0.45,
			stagger: 0.05,
			ease: 'power3.out'
		});
	});
	logo.addEventListener('mouseleave', function(){
		gsap.to(parts, {
			y: 0,
			scale: 1,
			rotation: 0,
			duration: 0.8,
			stagger: 0.05,
			ease: 'elastic.out(1, .45)'
		});
	});
}

© 2026 xoyop