diff --git a/README.md b/README.md index 483cf0c..2243d13 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,13 @@ SpreadSyncCMS =============== + +リンク +------- +* [sample1ページ](../../pages/sample1/index.html) +* [sample2ページ](../../pages/sample2/index.html) +* [sample3ページ](../../pages/sample3/index.html) +* [スプシID抽出&ドライブ画像リンク変換ツール ](../../pages/extractor/index.html) + +ページ|説明 +----------------|---------------------------- +ID抽出&URL変換ツール| 本システムを作成する際に、スプシIDとドライブ画像URLの変換が必要であり、それを自動で行うツールです。自分用です。 \ No newline at end of file diff --git a/extractor/index.html b/extractor/index.html new file mode 100644 index 0000000..55109d5 --- /dev/null +++ b/extractor/index.html @@ -0,0 +1,33 @@ + + + + + SpreadSheetIDExtractor + + + +

スプシID抽出 & ドライブ画像リンク変換ツール

+
+

本ツールはSpreadSyncCMSを使用する際に必要なID & 画像リンクを変換するツールです。IDはGASに記載する際にURLから抽出する必要があり、画像リンクはスプシのimgの行に書き込む際に変換が必要です。

+ +

スプレッドシートID抽出

+

GoogleスプレッドシートのURL内のIDを抽出します。

+

【抽出前】https://docs.google.com/spreadsheets/d/10OZa1MYV1zZVjOMZzoBglNwW0BRp55Wn2OQkjbaIGo8/edit#gid=771807520

+

【抽出後】10OZa1MYV1zZVjOMZzoBglNwW0BRp55Wn2OQkjbaIGo8

+ + + +
+ +

Drive画像リンク変換

+

Googleドライブの画像リンクをimgタグで利用できるURLに変換します。

+

【変換前】https://drive.google.com/file/d/1M0IIk14mg_G0eBf3yaLk1PD5JEz--6RA/view?usp=sharing

+

【変換後】https://lh3.google.com/u/o/d/1M0IIk14mg_G0eBf3yaLk1PD5JEz--6RA

+ + + +
+
+ + + diff --git a/extractor/script.js b/extractor/script.js new file mode 100644 index 0000000..f5002aa --- /dev/null +++ b/extractor/script.js @@ -0,0 +1,61 @@ +document.getElementById("spreadsheetUrlInput").addEventListener("blur", function() { + var url = this.value; + if(SpreadsheetUrl(url)) { + document.getElementById("spreadsheetIdDisplay").value = extractSpreadsheetId(url); + document.getElementById("spreadsheetWarning").textContent = ''; + } else { + document.getElementById("spreadsheetWarning").textContent = '正しいスプレッドシートのURLを入力してください。'; + } +}); + +document.getElementById("driveUrlInput").addEventListener("blur", function() { + var url = this.value; + if(DriveUrl(url)) { + document.getElementById("driveUrlDisplay").value = convertDriveUrlToImageTag(url); + document.getElementById("driveWarning").textContent = ''; + } else { + document.getElementById("driveWarning").textContent = '正しいドライブの共有リンクを入力してください。'; + } +}); + +function SpreadsheetUrl(url) { + return /\/spreadsheets\/d\/[a-zA-Z0-9-_]+/.test(url); +} + +function DriveUrl(url) { + return /\/file\/d\/[a-zA-Z0-9-_]+/.test(url); +} + +function extractSpreadsheetId(url) { + var matches = /\/spreadsheets\/d\/([a-zA-Z0-9-_]+)/.exec(url); + return matches ? matches[1] : ''; +} + +function convertDriveUrlToImageTag(url) { + var fileId = extractFileId(url); + return "https://lh3.google.com/u/o/d/" + fileId; +} + +function extractFileId(url) { + var matches = /\/file\/d\/([a-zA-Z0-9-_]+)/.exec(url); + return matches ? matches[1] : ''; +} + +document.getElementById("copySpreadsheetId").addEventListener("click", function() { + copyToClipboard("spreadsheetIdDisplay"); +}); + +document.getElementById("copyDriveUrl").addEventListener("click", function() { + copyToClipboard("driveUrlDisplay"); +}); + +function copyToClipboard(elementId) { + var copyText = document.getElementById(elementId).value; + navigator.clipboard.writeText(copyText) + .then(() => { + console.log('Text copied to clipboard'); + }) + .catch(err => { + console.error('Error in copying text: ', err); + }); +} \ No newline at end of file diff --git a/extractor/style.css b/extractor/style.css new file mode 100644 index 0000000..6bd8e3c --- /dev/null +++ b/extractor/style.css @@ -0,0 +1,87 @@ +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background-color: #f2f2f2; + color: #333; + padding: 20px; + line-height: 1.6; +} + +h1 { + color: #2c3e50; + font-size: 1.8em; + margin-bottom: 0.7em; + text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); + text-align: center; +} + +h2 { + color: #34495e; + font-size: 1.4em; + padding: 0 8px; + border-left: #4d7aa8 solid 4px; +} + +p { + color :#34495e; + font-size: 0.9em; +} + +input[type="text"], button { + width: 75%; + padding: 10px; + margin: 10px 0; + border-radius: 5px; + border: 1px solid #ccc; + box-shadow: 2px 2px 5px rgba(0,0,0,0.1); +} + +input[type="text"] { + box-sizing: border-box; +} + +button { + width: auto; + background-color: #4caf50; + color: white; + border: none; + cursor: pointer; + transition: background-color 0.3s ease; +} + +button:hover { + background-color: #45a049; +} + +.warning { + color: red; + margin-top: 5px; +} + +.container { + width: 70%; + margin: auto; + overflow:scroll +} + +@media screen and (max-width: 700px) { + h1 { + font-size: 1.3em; + } + + h2 { + font-size: 1.1em;; + } + + p { + font-size: 0.7em; + } + + .container { + width: 95%; + margin: 20px auto; + } + + input[type="text"], button { + width: 100%; + } +} diff --git a/sample1/index.html b/sample1/index.html new file mode 100644 index 0000000..7c9d4c8 --- /dev/null +++ b/sample1/index.html @@ -0,0 +1,25 @@ + + + + + + サンプル1のページ + + + + + +
+
+ + + + diff --git a/sample1/script.js b/sample1/script.js new file mode 100644 index 0000000..31c2bde --- /dev/null +++ b/sample1/script.js @@ -0,0 +1,113 @@ +// GASからJSONデータを取得してHTML要素を生成する +async function fetchAndGenerateData() { + const response = await fetch('https://script.google.com/macros/s/AKfycbwnDGuFxgTPOl1dBDrYx_MuqlrSYj3KsxgUCGEHDzexWYPHapDAg6KsuiIf_rfRGWe94Q/exec'); + const jsonData = await response.json(); + // HTML内の要素を取得 + const nameElement = document.getElementById('name'); + const eventContainer = document.getElementById('eventContainer'); + + nameElement.textContent = jsonData[0].areaID; + + const categories = {}; + // JSONデータをもとに要素を生成 + for (const data of jsonData) { + const category = data.category; + if (!categories[category]) { + categories[category] = []; + } + categories[category].push(data); + } + + for (const category in categories) { + const categoryId = categories[category].length; + const categoryContainer = createCategoryContainer(category, categoryId); + + // カテゴリーごとにメニューを追加できるようにした + for (const data of categories[category]) { + const eventDiv = createEventElement(data); + categoryContainer.appendChild(eventDiv); + } + eventContainer.appendChild(categoryContainer); + } +} + +// カテゴリーごとのコンテナを生成 +function createCategoryContainer(category, categoryId) { + const categoryContainer = document.createElement('div'); + categoryContainer.classList.add('categoryContainer'); + + const h2 = document.createElement('h2'); + h2.classList.add('category'); + h2.textContent = category; + h2.id = `category-${categoryId}`; + eventContainer.appendChild(h2); + + const navLink = document.createElement('a'); + navLink.href = `#category-${categoryId}`; + navLink.textContent = category; + const navItem = document.createElement('li'); + navItem.appendChild(navLink); + document.querySelector('.navbar ul').appendChild(navItem); + + return categoryContainer; +} + +// イベント要素を生成 +function createEventElement(data) { + const div = document.createElement('div'); + div.classList.add('event-item'); + + if (data.pageLink) { + const a = document.createElement('a'); + a.href = data.pageLink; + a.target = '_blank'; + div.appendChild(a); + + const img = createImageElement(data.img); + a.appendChild(img); + } else { + const img = createImageElement(data.img); + div.appendChild(img); + } + + const h3 = createHeadingElement('h3', 'eventName', data.eventName); + div.appendChild(h3); + + if (data.location) { + const p1 = createParagraphElement('p', 'location', `場所: ${data.location}`); + div.appendChild(p1); + } + + if (data.date) { + const p2 = createParagraphElement('p', 'date', `開催期間: ${data.date}${data.inSession === 'O' ? ' (終了)' : ''}`); + div.appendChild(p2); + } + + return div; +} + +// 画像要素を生成 +function createImageElement(imgSrc) { + const img = document.createElement('img'); + img.src = imgSrc; + return img; +} + +// ヘッディング要素を生成 +function createHeadingElement(tag, className, textContent) { + const element = document.createElement(tag); + element.classList.add(className); + element.textContent = textContent; + return element; +} + +// 段落要素を生成 +function createParagraphElement(tag, className, textContent) { + const element = document.createElement(tag); + element.classList.add(className); + element.textContent = textContent; + return element; +} + +// ページ読み込み時にJSONデータを取得してHTML要素を生成 +window.addEventListener('DOMContentLoaded', fetchAndGenerateData); diff --git a/sample1/style.css b/sample1/style.css new file mode 100644 index 0000000..2cdedcf --- /dev/null +++ b/sample1/style.css @@ -0,0 +1,155 @@ +html{ + scroll-behavior: smooth; + scroll-padding-top: 100px; +} + +body { + font-family: 'Noto Sans JP', sans-serif; + margin: 0; + padding: 0; + background-color: #f4f4f4; + width: 100%; +} + +p{ + margin: 2% 2%; + font-size:clamp(0.875rem, 0.818rem + 0.24vw, 1rem); +} + +.navbar { + background-color: #02465b; + color: #f4f4f4; + width: 100%; + position: sticky;/* 2行だけの記述でfixedと同じ配置ができる*/ + top: 0; + z-index: 100; + box-shadow: 0px 4px 8px #adadad; +} + +.barContainer { + width: 80%; + margin: auto; + padding: 1em 0; + display: flex; + justify-content: space-between; + align-items: center; +} + +.navbar h1 { + margin: 0; + padding: 0; + font-size: clamp(1.75rem, 1.693rem + 0.24vw, 1.875rem); +} + +.navbar nav ul { + list-style: none; + margin: 0; + padding: 0; + display: flex; +} + +.navbar nav ul li { + margin-right: 1em; +} + +.navbar nav ul li a { + text-decoration: none; + color: #f4f4f4; +} + +.navbar nav ul li a:hover { + border-bottom: 2px solid #ccb540; +} + +/* ここまでは共通で記載する */ +.category{ + border-bottom: 1px solid #acacac; + width: 100%; +} +.categoryContainer{ + display: grid; + grid-template-columns: repeat(auto-fit, 300px); + justify-content: center; + grid-gap:1em; + /* + ウィンドウに合わせて自動で改行(中央揃え左揃え)を再現するにはflexboxでは難しかった。 + flex-wrap:wrapとjustify-content:centerでは改行した時に真ん中配置から始まっちゃう(>_<) + しかし、gridなら4行でいけた。もっと短くできるかも。 + */ +} +#eventContainer { + width: 98%; + margin:0 auto; +} + +.event-item { + background-color: #ffffff; + border-radius: 10px; + box-shadow: 0px 0px 8px #acacac; + padding: 0; + text-align: center; + width: 100%; + margin: .5em auto; +} + +.event-item:hover { + transform: scale(1.1); + transition: transform 0.3s ease; +} + +.event-item img { + width: 100%; + height: 25vh; + object-fit: cover; + border-radius: 10px 10px 0 0 ; + padding: 0; +} + +.event-item a img:hover{ + opacity:0.5; +} + +.event-item h3 { + font-size: clamp(1rem, 0.943rem + 0.24vw, 1.125rem); + margin: 0 1em; + border-bottom: 2px solid #acacac; + text-align: center; +} + +@media screen and (max-width: 1036px){ + .navbar{ + width: 100%; + } + #eventContainer{ + width: 95%; + margin: 0 auto; + } + .category{ + width: 80%; + margin: 1em auto; + } + + @media screen and (max-width: 820px){ + .category{ + text-align: center; + } + .barContainer { + width: 80%; + margin: auto; + padding: 1em 0; + flex-direction: column; + } + + @media screen and (max-width: 430px){ + .categoryContainer{ + display: block; + } + .event-item{ + width: 90%; + margin-bottom: 10%; + } + .barContainer { + width: 95%; + } + } +} \ No newline at end of file diff --git a/sample2/index.html b/sample2/index.html new file mode 100644 index 0000000..15f0627 --- /dev/null +++ b/sample2/index.html @@ -0,0 +1,25 @@ + + + + + + サンプル2のページ + + + + + +
+
+ + + + diff --git a/sample2/script.js b/sample2/script.js new file mode 100644 index 0000000..3f2b71a --- /dev/null +++ b/sample2/script.js @@ -0,0 +1,113 @@ +// GASからJSONデータを取得してHTML要素を生成する +async function fetchAndGenerateData() { + const response = await fetch('https://script.google.com/macros/s/AKfycbwTOaOZkom7XpWBvlDCBf6pv7MYqag0BT1Lu0H-a4ZS9rM5DEHBhGlQFv-zys70RL1Kng/exec'); + const jsonData = await response.json(); + // HTML内の要素を取得 + const nameElement = document.getElementById('name'); + const eventContainer = document.getElementById('eventContainer'); + + nameElement.textContent = jsonData[0].areaID; + + const categories = {}; + // JSONデータをもとに要素を生成 + for (const data of jsonData) { + const category = data.category; + if (!categories[category]) { + categories[category] = []; + } + categories[category].push(data); + } + + for (const category in categories) { + const categoryId = categories[category].length; + const categoryContainer = createCategoryContainer(category, categoryId); + + // カテゴリーごとにメニューを追加できるようにした + for (const data of categories[category]) { + const eventDiv = createEventElement(data); + categoryContainer.appendChild(eventDiv); + } + eventContainer.appendChild(categoryContainer); + } +} + +// カテゴリーごとのコンテナを生成 +function createCategoryContainer(category, categoryId) { + const categoryContainer = document.createElement('div'); + categoryContainer.classList.add('categoryContainer'); + + const h2 = document.createElement('h2'); + h2.classList.add('category'); + h2.textContent = category; + h2.id = `category-${categoryId}`; + eventContainer.appendChild(h2); + + const navLink = document.createElement('a'); + navLink.href = `#category-${categoryId}`; + navLink.textContent = category; + const navItem = document.createElement('li'); + navItem.appendChild(navLink); + document.querySelector('.navbar ul').appendChild(navItem); + + return categoryContainer; +} + +// イベント要素を生成 +function createEventElement(data) { + const div = document.createElement('div'); + div.classList.add('event-item'); + + if (data.pageLink) { + const a = document.createElement('a'); + a.href = data.pageLink; + a.target = '_blank'; + div.appendChild(a); + + const img = createImageElement(data.img); + a.appendChild(img); + } else { + const img = createImageElement(data.img); + div.appendChild(img); + } + + const h3 = createHeadingElement('h3', 'eventName', data.eventName); + div.appendChild(h3); + + if (data.location) { + const p1 = createParagraphElement('p', 'location', `場所: ${data.location}`); + div.appendChild(p1); + } + + if (data.date) { + const p2 = createParagraphElement('p', 'date', `開催期間: ${data.date}${data.inSession === 'O' ? ' (終了)' : ''}`); + div.appendChild(p2); + } + + return div; +} + +// 画像要素を生成 +function createImageElement(imgSrc) { + const img = document.createElement('img'); + img.src = imgSrc; + return img; +} + +// ヘッディング要素を生成 +function createHeadingElement(tag, className, textContent) { + const element = document.createElement(tag); + element.classList.add(className); + element.textContent = textContent; + return element; +} + +// 段落要素を生成 +function createParagraphElement(tag, className, textContent) { + const element = document.createElement(tag); + element.classList.add(className); + element.textContent = textContent; + return element; +} + +// ページ読み込み時にJSONデータを取得してHTML要素を生成 +window.addEventListener('DOMContentLoaded', fetchAndGenerateData); diff --git a/sample2/style.css b/sample2/style.css new file mode 100644 index 0000000..2cdedcf --- /dev/null +++ b/sample2/style.css @@ -0,0 +1,155 @@ +html{ + scroll-behavior: smooth; + scroll-padding-top: 100px; +} + +body { + font-family: 'Noto Sans JP', sans-serif; + margin: 0; + padding: 0; + background-color: #f4f4f4; + width: 100%; +} + +p{ + margin: 2% 2%; + font-size:clamp(0.875rem, 0.818rem + 0.24vw, 1rem); +} + +.navbar { + background-color: #02465b; + color: #f4f4f4; + width: 100%; + position: sticky;/* 2行だけの記述でfixedと同じ配置ができる*/ + top: 0; + z-index: 100; + box-shadow: 0px 4px 8px #adadad; +} + +.barContainer { + width: 80%; + margin: auto; + padding: 1em 0; + display: flex; + justify-content: space-between; + align-items: center; +} + +.navbar h1 { + margin: 0; + padding: 0; + font-size: clamp(1.75rem, 1.693rem + 0.24vw, 1.875rem); +} + +.navbar nav ul { + list-style: none; + margin: 0; + padding: 0; + display: flex; +} + +.navbar nav ul li { + margin-right: 1em; +} + +.navbar nav ul li a { + text-decoration: none; + color: #f4f4f4; +} + +.navbar nav ul li a:hover { + border-bottom: 2px solid #ccb540; +} + +/* ここまでは共通で記載する */ +.category{ + border-bottom: 1px solid #acacac; + width: 100%; +} +.categoryContainer{ + display: grid; + grid-template-columns: repeat(auto-fit, 300px); + justify-content: center; + grid-gap:1em; + /* + ウィンドウに合わせて自動で改行(中央揃え左揃え)を再現するにはflexboxでは難しかった。 + flex-wrap:wrapとjustify-content:centerでは改行した時に真ん中配置から始まっちゃう(>_<) + しかし、gridなら4行でいけた。もっと短くできるかも。 + */ +} +#eventContainer { + width: 98%; + margin:0 auto; +} + +.event-item { + background-color: #ffffff; + border-radius: 10px; + box-shadow: 0px 0px 8px #acacac; + padding: 0; + text-align: center; + width: 100%; + margin: .5em auto; +} + +.event-item:hover { + transform: scale(1.1); + transition: transform 0.3s ease; +} + +.event-item img { + width: 100%; + height: 25vh; + object-fit: cover; + border-radius: 10px 10px 0 0 ; + padding: 0; +} + +.event-item a img:hover{ + opacity:0.5; +} + +.event-item h3 { + font-size: clamp(1rem, 0.943rem + 0.24vw, 1.125rem); + margin: 0 1em; + border-bottom: 2px solid #acacac; + text-align: center; +} + +@media screen and (max-width: 1036px){ + .navbar{ + width: 100%; + } + #eventContainer{ + width: 95%; + margin: 0 auto; + } + .category{ + width: 80%; + margin: 1em auto; + } + + @media screen and (max-width: 820px){ + .category{ + text-align: center; + } + .barContainer { + width: 80%; + margin: auto; + padding: 1em 0; + flex-direction: column; + } + + @media screen and (max-width: 430px){ + .categoryContainer{ + display: block; + } + .event-item{ + width: 90%; + margin-bottom: 10%; + } + .barContainer { + width: 95%; + } + } +} \ No newline at end of file diff --git a/sample3/index.html b/sample3/index.html new file mode 100644 index 0000000..15f0627 --- /dev/null +++ b/sample3/index.html @@ -0,0 +1,25 @@ + + + + + + サンプル2のページ + + + + + +
+
+ + + + diff --git a/sample3/script.js b/sample3/script.js new file mode 100644 index 0000000..8c6d850 --- /dev/null +++ b/sample3/script.js @@ -0,0 +1,113 @@ +// GASからJSONデータを取得してHTML要素を生成する +async function fetchAndGenerateData() { + const response = await fetch('https://script.google.com/macros/s/AKfycbzawq6e7Ojx2evDE3qxGCEvngtMmCKADwSixvmpFO8j9Hdnh9eYlBBUPe_nsI4ZbwD2/exec'); + const jsonData = await response.json(); + // HTML内の要素を取得 + const nameElement = document.getElementById('name'); + const eventContainer = document.getElementById('eventContainer'); + + nameElement.textContent = jsonData[0].areaID; + + const categories = {}; + // JSONデータをもとに要素を生成 + for (const data of jsonData) { + const category = data.category; + if (!categories[category]) { + categories[category] = []; + } + categories[category].push(data); + } + + for (const category in categories) { + const categoryId = categories[category].length; + const categoryContainer = createCategoryContainer(category, categoryId); + + // カテゴリーごとにメニューを追加できるようにした + for (const data of categories[category]) { + const eventDiv = createEventElement(data); + categoryContainer.appendChild(eventDiv); + } + eventContainer.appendChild(categoryContainer); + } +} + +// カテゴリーごとのコンテナを生成 +function createCategoryContainer(category, categoryId) { + const categoryContainer = document.createElement('div'); + categoryContainer.classList.add('categoryContainer'); + + const h2 = document.createElement('h2'); + h2.classList.add('category'); + h2.textContent = category; + h2.id = `category-${categoryId}`; + eventContainer.appendChild(h2); + + const navLink = document.createElement('a'); + navLink.href = `#category-${categoryId}`; + navLink.textContent = category; + const navItem = document.createElement('li'); + navItem.appendChild(navLink); + document.querySelector('.navbar ul').appendChild(navItem); + + return categoryContainer; +} + +// イベント要素を生成 +function createEventElement(data) { + const div = document.createElement('div'); + div.classList.add('event-item'); + + if (data.pageLink) { + const a = document.createElement('a'); + a.href = data.pageLink; + a.target = '_blank'; + div.appendChild(a); + + const img = createImageElement(data.img); + a.appendChild(img); + } else { + const img = createImageElement(data.img); + div.appendChild(img); + } + + const h3 = createHeadingElement('h3', 'eventName', data.eventName); + div.appendChild(h3); + + if (data.location) { + const p1 = createParagraphElement('p', 'location', `場所: ${data.location}`); + div.appendChild(p1); + } + + if (data.date) { + const p2 = createParagraphElement('p', 'date', `開催期間: ${data.date}${data.inSession === 'O' ? ' (終了)' : ''}`); + div.appendChild(p2); + } + + return div; +} + +// 画像要素を生成 +function createImageElement(imgSrc) { + const img = document.createElement('img'); + img.src = imgSrc; + return img; +} + +// ヘッディング要素を生成 +function createHeadingElement(tag, className, textContent) { + const element = document.createElement(tag); + element.classList.add(className); + element.textContent = textContent; + return element; +} + +// 段落要素を生成 +function createParagraphElement(tag, className, textContent) { + const element = document.createElement(tag); + element.classList.add(className); + element.textContent = textContent; + return element; +} + +// ページ読み込み時にJSONデータを取得してHTML要素を生成 +window.addEventListener('DOMContentLoaded', fetchAndGenerateData); diff --git a/sample3/style.css b/sample3/style.css new file mode 100644 index 0000000..2cdedcf --- /dev/null +++ b/sample3/style.css @@ -0,0 +1,155 @@ +html{ + scroll-behavior: smooth; + scroll-padding-top: 100px; +} + +body { + font-family: 'Noto Sans JP', sans-serif; + margin: 0; + padding: 0; + background-color: #f4f4f4; + width: 100%; +} + +p{ + margin: 2% 2%; + font-size:clamp(0.875rem, 0.818rem + 0.24vw, 1rem); +} + +.navbar { + background-color: #02465b; + color: #f4f4f4; + width: 100%; + position: sticky;/* 2行だけの記述でfixedと同じ配置ができる*/ + top: 0; + z-index: 100; + box-shadow: 0px 4px 8px #adadad; +} + +.barContainer { + width: 80%; + margin: auto; + padding: 1em 0; + display: flex; + justify-content: space-between; + align-items: center; +} + +.navbar h1 { + margin: 0; + padding: 0; + font-size: clamp(1.75rem, 1.693rem + 0.24vw, 1.875rem); +} + +.navbar nav ul { + list-style: none; + margin: 0; + padding: 0; + display: flex; +} + +.navbar nav ul li { + margin-right: 1em; +} + +.navbar nav ul li a { + text-decoration: none; + color: #f4f4f4; +} + +.navbar nav ul li a:hover { + border-bottom: 2px solid #ccb540; +} + +/* ここまでは共通で記載する */ +.category{ + border-bottom: 1px solid #acacac; + width: 100%; +} +.categoryContainer{ + display: grid; + grid-template-columns: repeat(auto-fit, 300px); + justify-content: center; + grid-gap:1em; + /* + ウィンドウに合わせて自動で改行(中央揃え左揃え)を再現するにはflexboxでは難しかった。 + flex-wrap:wrapとjustify-content:centerでは改行した時に真ん中配置から始まっちゃう(>_<) + しかし、gridなら4行でいけた。もっと短くできるかも。 + */ +} +#eventContainer { + width: 98%; + margin:0 auto; +} + +.event-item { + background-color: #ffffff; + border-radius: 10px; + box-shadow: 0px 0px 8px #acacac; + padding: 0; + text-align: center; + width: 100%; + margin: .5em auto; +} + +.event-item:hover { + transform: scale(1.1); + transition: transform 0.3s ease; +} + +.event-item img { + width: 100%; + height: 25vh; + object-fit: cover; + border-radius: 10px 10px 0 0 ; + padding: 0; +} + +.event-item a img:hover{ + opacity:0.5; +} + +.event-item h3 { + font-size: clamp(1rem, 0.943rem + 0.24vw, 1.125rem); + margin: 0 1em; + border-bottom: 2px solid #acacac; + text-align: center; +} + +@media screen and (max-width: 1036px){ + .navbar{ + width: 100%; + } + #eventContainer{ + width: 95%; + margin: 0 auto; + } + .category{ + width: 80%; + margin: 1em auto; + } + + @media screen and (max-width: 820px){ + .category{ + text-align: center; + } + .barContainer { + width: 80%; + margin: auto; + padding: 1em 0; + flex-direction: column; + } + + @media screen and (max-width: 430px){ + .categoryContainer{ + display: block; + } + .event-item{ + width: 90%; + margin-bottom: 10%; + } + .barContainer { + width: 95%; + } + } +} \ No newline at end of file