├── .node-version ├── src ├── scss │ ├── global │ │ ├── _index.scss │ │ └── _variable.scss │ ├── style.scss │ ├── foundation │ │ ├── _index.scss │ │ ├── _common.scss │ │ └── _normalize.scss │ └── component │ │ ├── _about.scss │ │ ├── _cover.scss │ │ ├── _index.scss │ │ ├── _store.scss │ │ ├── _nav-share.scss │ │ ├── _section.scss │ │ ├── _embeddedPlayer.scss │ │ ├── _track-table.scss │ │ ├── _container.scss │ │ ├── _organization.scss │ │ ├── _gallery.scss │ │ ├── _button.scss │ │ ├── _member.scss │ │ ├── _overview.scss │ │ ├── _setup.scss │ │ ├── _prebuild-banner.scss │ │ └── _footer.scss ├── templates │ ├── _partial │ │ ├── _footer.ejs │ │ ├── _header.ejs │ │ └── _logo.ejs │ └── pages │ │ ├── index.ejs │ │ └── preview.ejs └── js │ ├── index │ ├── index.js │ └── vanilla-tilt.min.js │ ├── i18n │ └── i18n-language.js │ └── preview │ ├── csv.min.js │ └── preview.js ├── tokusetsu4.code-workspace ├── bs-config.js ├── README.md ├── LICENSE ├── package.json └── .gitignore /.node-version: -------------------------------------------------------------------------------- 1 | v16.16.0 2 | -------------------------------------------------------------------------------- /src/scss/global/_index.scss: -------------------------------------------------------------------------------- 1 | @forward '_variable'; 2 | -------------------------------------------------------------------------------- /src/scss/style.scss: -------------------------------------------------------------------------------- 1 | @use 'foundation'; 2 | @use 'component'; 3 | -------------------------------------------------------------------------------- /src/scss/foundation/_index.scss: -------------------------------------------------------------------------------- 1 | @forward '_normalize'; 2 | @forward '_common'; 3 | -------------------------------------------------------------------------------- /tokusetsu4.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /src/scss/component/_about.scss: -------------------------------------------------------------------------------- 1 | @use "../global" as g; 2 | 3 | .about-content { 4 | 5 | .about { 6 | margin: 0; 7 | &:not(:first-child) { 8 | margin-top: var(--space-4); 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/templates/_partial/_footer.ejs: -------------------------------------------------------------------------------- 1 | <% if (pageId === 'preview') { %> 2 | 3 | 4 | <% } %> 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/scss/component/_cover.scss: -------------------------------------------------------------------------------- 1 | @use "../global" as g; 2 | 3 | .cover { 4 | max-width: var(--col-width-2xl); 5 | margin-left: auto; 6 | margin-right: auto; 7 | img { 8 | width: 100%; 9 | max-width: 100%; 10 | display: block; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /bs-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | files: [ 3 | 'build/**/*.css', 4 | 'build/**/*.js', 5 | 'build/**/*.html', 6 | ], 7 | server: { 8 | baseDir: "build" 9 | }, 10 | open: false, 11 | socket: { 12 | domain: 'localhost:3000' 13 | }, 14 | https: true, 15 | notify: false, 16 | }; 17 | -------------------------------------------------------------------------------- /src/scss/component/_index.scss: -------------------------------------------------------------------------------- 1 | @use "_button"; 2 | @use "_container"; 3 | @use "_section"; 4 | @use "_cover"; 5 | @use "_overview"; 6 | @use "_store"; 7 | @use "_nav-share"; 8 | @use "_embeddedPlayer"; 9 | @use "_about"; 10 | @use "_gallery"; 11 | @use "_track-table"; 12 | @use "_member"; 13 | @use "_organization"; 14 | @use "_footer"; 15 | @use "_prebuild-banner"; 16 | @use "_setup"; 17 | -------------------------------------------------------------------------------- /src/scss/foundation/_common.scss: -------------------------------------------------------------------------------- 1 | // Common 2 | * { 3 | box-sizing: border-box; 4 | word-wrap: break-word; 5 | word-break: break-word; 6 | } 7 | html{ 8 | scroll-behavior: smooth; 9 | } 10 | body { 11 | font-family: var(--font); 12 | background-color: var(--color-bg); 13 | color: var(--color-text); 14 | line-height: var(--line-height-base); 15 | font-size: var(--font-size-100); 16 | word-wrap: break-word; 17 | } 18 | -------------------------------------------------------------------------------- /src/scss/component/_store.scss: -------------------------------------------------------------------------------- 1 | @use "../global" as g; 2 | 3 | .section-store { 4 | text-align: center; 5 | margin: var(--space-5) auto; 6 | } 7 | 8 | .store-heading { 9 | font-size: var(--font-size-400); 10 | line-height: var(--line-height-sm); 11 | margin: 0 0 var(--space-3); 12 | } 13 | .store-wrap { 14 | display: flex; 15 | flex-wrap: wrap; 16 | justify-content: center; 17 | & > * { 18 | margin: var(--space-1); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/scss/component/_nav-share.scss: -------------------------------------------------------------------------------- 1 | @use "../global" as g; 2 | 3 | 4 | .nav-share { 5 | margin: var(--space-5) auto; 6 | display: flex; 7 | gap: var(--space-2); 8 | justify-content: center; 9 | } 10 | .share-btn { 11 | display: flex; 12 | border-radius: 50%; 13 | width: 48px; 14 | height: 48px; 15 | align-items: center; 16 | justify-content: center; 17 | } 18 | .share-tw { 19 | background-color: var(--color-btn-tw); 20 | } 21 | .share-fb { 22 | background-color: var(--color-btn-fb); 23 | } 24 | -------------------------------------------------------------------------------- /src/scss/component/_section.scss: -------------------------------------------------------------------------------- 1 | @use "../global" as g; 2 | 3 | .section { 4 | margin: var(--space-7) auto; 5 | padding-top: var(--space-4); 6 | & + .section { 7 | border-top: 1px solid var(--color-border); 8 | } 9 | } 10 | .section-wrapper { 11 | display: grid; 12 | gap: var(--space-3); 13 | @media #{g.$mq-lg} { 14 | grid-template-columns: 1fr 1.5fr; 15 | } 16 | } 17 | .section-header { 18 | h2 { 19 | margin: 0; 20 | font-size: var(--font-size-400); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/scss/component/_embeddedPlayer.scss: -------------------------------------------------------------------------------- 1 | // embeddedPlayer 2 | 3 | .embeddedPlayer-wrapper { 4 | max-width: 700px; 5 | margin: var(--space-5) auto; 6 | display: grid; 7 | gap: var(--space-4); 8 | } 9 | .embeddedPlayer { 10 | position: relative; 11 | padding-bottom: 56.25%; 12 | padding-top: 30px; 13 | height: 100%; 14 | overflow: hidden; 15 | text-align: center; 16 | iframe, 17 | object, 18 | embed { 19 | position: absolute; 20 | top: 0; 21 | left: 0; 22 | width: 100%; 23 | height: 100%; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/scss/component/_track-table.scss: -------------------------------------------------------------------------------- 1 | @use "../global" as g; 2 | 3 | .track-table { 4 | display: grid; 5 | gap: var(--space-3); 6 | } 7 | .track-tr { 8 | counter-increment: list; 9 | display: grid; 10 | grid-template-columns: auto 1fr; 11 | gap: var(--space-2); 12 | } 13 | .track-th { 14 | font-size: var(--font-size-200); 15 | color: var(--color-text-highlight); 16 | min-width: 1.5em; 17 | &::before { 18 | content: counter(list); 19 | } 20 | } 21 | .track-heading { 22 | font-weight: bold; 23 | font-size: var(--font-size-200); 24 | margin: 0; 25 | } 26 | .track-description { 27 | color: var(--color-text-secondary); 28 | } 29 | -------------------------------------------------------------------------------- /src/scss/component/_container.scss: -------------------------------------------------------------------------------- 1 | @use "../global" as g; 2 | 3 | .container { 4 | @include g.container(); 5 | position: relative; 6 | padding: var(--space-4) var(--space-3); 7 | @media #{g.$mq-md} { 8 | margin-top: var(--space-6); 9 | margin-bottom: var(--space-6); 10 | padding: var(--space-6); 11 | } 12 | } 13 | 14 | .containerMask { 15 | position: absolute; 16 | top: 0; 17 | left: 0; 18 | width: 100%; 19 | height: 100%; 20 | @media #{g.$mq-md} { 21 | border-radius: var(--border-radius-base); 22 | } 23 | // マスク有効時 24 | .is-bgMask-enabled & { 25 | background-color: var(--color-bg-content); 26 | } 27 | } 28 | 29 | .container-inner { 30 | position: relative; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/scss/component/_organization.scss: -------------------------------------------------------------------------------- 1 | .section-organization { 2 | display: flex; 3 | justify-content: center; 4 | flex-direction: column; 5 | align-items: center; 6 | } 7 | .organization-links { 8 | display: flex; 9 | flex-wrap: wrap; 10 | justify-content: center; 11 | & > * { 12 | margin: var(--space-1); 13 | } 14 | } 15 | .organization-link { 16 | border: 1px solid var(--color-border-highlight); 17 | color: var(--color-text-highlight); 18 | text-decoration: none; 19 | display: inline-block; 20 | padding: var(--space-1) var(--space-2); 21 | border-radius: var(--border-radius-sm); 22 | font-size: var(--font-size-75); 23 | line-height: var(--line-height-xs); 24 | } 25 | .organization-logo { 26 | margin: 0 0 var(--space-4); 27 | .organization-logo-img { 28 | display: block; 29 | max-width: 250px; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Tokusetsu 4 3 |

4 |

The most doujin-friently landing page builder

5 |

6 | Introduction 7 | · 8 | Tutorial 9 |

10 | 11 | # For developers 12 | 13 | ## Set up 14 | 15 | ``` 16 | $ git clone git@github.com:sanographix/tokusetsu4.git tokusetsu4 17 | $ cd tokusetsu4 18 | $ npm install 19 | ``` 20 | 21 | ## Start local server 22 | 23 | ``` 24 | $ npm start 25 | ``` 26 | 27 | Default URL is . 28 | 29 | ## Build 30 | 31 | ``` 32 | $ npm run build 33 | ``` 34 | 35 | Assets will output to `build/`. 36 | 37 | # Author 38 | 39 | ### Showkaku Sano (sanographix) 40 | 41 | - 42 | - Twitter: [@sanographix](https://twitter.com/sanographix/) 43 | 44 | # License 45 | 46 | MIT 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) SANOGRAPHIX 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /src/templates/_partial/_header.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | <% if (pageId === 'setup') { %>Set up Tokusetsu 4<% } else if (pageId === 7 | 'preview') {%><% } %> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | <% if (pageId === 'preview') { %> 18 | 19 | <% } %> 20 | 21 | 22 | 23 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/scss/component/_gallery.scss: -------------------------------------------------------------------------------- 1 | @use "../global" as g; 2 | 3 | .section-gallery-wrapper { 4 | display: grid; 5 | gap: var(--space-3); 6 | } 7 | 8 | .gallery-items { 9 | margin: 0; 10 | padding: 0; 11 | list-style: none; 12 | display: grid; 13 | grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); 14 | gap: var(--space-3); 15 | .gallery-img { 16 | max-width: 100%; 17 | display: block; 18 | cursor: zoom-in; 19 | } 20 | } 21 | 22 | // lightbox 23 | .gallery-lightbox { 24 | display: none; 25 | @media #{g.$mq-sm} { 26 | cursor: zoom-out; 27 | &.is-open { 28 | display: flex; 29 | align-items: center; 30 | justify-content: center; 31 | position: fixed; 32 | top: 0; 33 | left: 0; 34 | width: 100%; 35 | height: 100%; 36 | z-index: 10; 37 | background-color: rgba(0,0,0,.75); 38 | img { 39 | max-width: 100%; 40 | max-height: 100%; 41 | } 42 | } 43 | } 44 | } 45 | 46 | // Lightboxが開いてるときはスクロールさせない 47 | body.is-lightbox-opened { 48 | @media #{g.$mq-sm} { 49 | overflow: hidden; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/scss/component/_button.scss: -------------------------------------------------------------------------------- 1 | @use "../global" as g; 2 | 3 | .button { 4 | display: inline-block; 5 | padding: calc(var(--space-2) + var(--space-1)) var(--space-3); 6 | line-height: var(--line-height-sm); 7 | font-family: inherit; 8 | font-size: var(--font-size-75); 9 | letter-spacing: var(--letter-spacing-2); 10 | text-transform: uppercase; 11 | text-decoration: none; 12 | text-align: center; 13 | transition: all .25s; 14 | border: 0; 15 | border-radius: var(--border-radius-rounded); 16 | cursor: pointer; 17 | @media #{g.$mq-sm} { 18 | padding: calc(var(--space-2) + var(--space-1)) var(--space-4); 19 | } 20 | } 21 | .button-primary { 22 | background: var(--color-btn-primary-bg); 23 | color: var(--color-btn-primary-text); 24 | &:hover { 25 | filter: brightness(1.15); 26 | transform: scale(1.1,1.1); 27 | } 28 | } 29 | .button-primary-ghost { 30 | color: var(--color-btn-primary-ghost-text); 31 | box-shadow: inset 0 0 0 1px var(--color-btn-primary-ghost-border); 32 | &:hover { 33 | background: var(--color-btn-primary-bg); 34 | color: var(--color-btn-primary-text); 35 | } 36 | } 37 | .button-large { 38 | min-width: 10em; 39 | padding: var(--space-3) var(--space-4); 40 | font-size: var(--font-size-200); 41 | } 42 | -------------------------------------------------------------------------------- /src/scss/component/_member.scss: -------------------------------------------------------------------------------- 1 | @use "../global" as g; 2 | 3 | .member-wrap { 4 | display: grid; 5 | gap: var(--space-3); 6 | } 7 | .member { 8 | display: grid; 9 | align-items: center; 10 | @media #{g.$mq-md} { 11 | gap: var(--space-4); 12 | grid-template-columns: 1fr 1.25fr; 13 | } 14 | } 15 | .member-role { 16 | color: var(--color-text-secondary); 17 | @media #{g.$mq-md} { 18 | display: flex; 19 | align-items: center; 20 | gap: var(--space-2); 21 | &::after { 22 | content: ''; 23 | background-color: var(--color-border); 24 | height: 1px; 25 | flex: 1; 26 | } 27 | } 28 | } 29 | .member-content { 30 | } 31 | .member-name { 32 | font-size: var(--font-size-200); 33 | font-weight: bold; 34 | } 35 | .member-link { 36 | display: inline-block; 37 | margin-left: var(--space-2); 38 | position: relative; 39 | top: -.25em; 40 | } 41 | .member-url { 42 | border: 1px solid var(--color-border-highlight); 43 | color: var(--color-text-highlight); 44 | text-decoration: none; 45 | display: inline-block; 46 | padding: var(--space-1) var(--space-2); 47 | border-radius: var(--border-radius-sm); 48 | font-size: var(--font-size-50); 49 | text-transform: uppercase; 50 | line-height: var(--line-height-xs); 51 | } 52 | -------------------------------------------------------------------------------- /src/scss/component/_overview.scss: -------------------------------------------------------------------------------- 1 | @use "../global" as g; 2 | 3 | 4 | .overview { 5 | display: grid; 6 | align-items: center; 7 | gap: var(--space-6); 8 | @media #{g.$mq-md} { 9 | grid-template-columns: 1fr 1fr; 10 | } 11 | @media #{g.$mq-lg} { 12 | grid-template-columns: 420px 1fr; 13 | } 14 | } 15 | .overview-main { 16 | } 17 | .overview-title { 18 | margin: 0; 19 | font-size: var(--font-size-400); 20 | line-height: var(--line-height-sm); 21 | } 22 | .organization-name { 23 | margin: 0; 24 | font-weight: normal; 25 | font-size: var(--font-size-75); 26 | } 27 | .overview-art-wrapper { 28 | margin: 0 10%; 29 | @media #{g.$mq-md} { 30 | margin: unset; 31 | } 32 | } 33 | .overview-art { 34 | .art-img { 35 | width: 100%; 36 | display: block; 37 | margin: auto; 38 | } 39 | 40 | } 41 | .art-empty { 42 | position: relative; 43 | padding-top: 100%; 44 | border: 1px solid var(--color-border); 45 | .label { 46 | position: absolute; 47 | top: 0; 48 | left: 0; 49 | width: 100%; 50 | height: 100%; 51 | display: flex; 52 | flex-direction: column; 53 | justify-content: center; 54 | align-items: center; 55 | color: var(--color-text-secondary); 56 | } 57 | } 58 | 59 | .overview-table { 60 | margin-top: var(--space-4); 61 | } 62 | .overview-label { 63 | color: var(--color-text-highlight); 64 | font-size: var(--font-size-75); 65 | text-transform: uppercase; 66 | font-weight: bold; 67 | &:not(:first-child) { 68 | margin-top: var(--space-3); 69 | } 70 | } 71 | .overview-content { 72 | margin: 0; 73 | a { 74 | color: inherit; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/js/index/index.js: -------------------------------------------------------------------------------- 1 | /*@license 2 | * 3 | * Tokusetsu 4: 4 | * licenses: MIT 5 | * Copyright (c) 2022 sanographix 6 | * https://github.com/sanographix/tokusetsu4 7 | * vanilla-tilt.js: 8 | * licenses: MIT 9 | * Copyright (c) 2017 Șandor Sergiu 10 | * https://github.com/micku7zu/vanilla-tilt.js 11 | */ 12 | 13 | // gallery 14 | (function() { 15 | window.addEventListener("load", function () { 16 | const samples = document.querySelectorAll('.js-gallery-item'); 17 | const lightboxes = document.querySelectorAll('.js-gallery-lightbox'); 18 | if (samples.length < 1) { return false; } 19 | Array.prototype.forEach.call(samples, function (sampleElem) { 20 | sampleElem.addEventListener('click', function () { 21 | const sampleIndex = sampleElem.dataset['index']; 22 | const lightbox = document.querySelector('.js-gallery-lightbox[data-index="' + sampleIndex + '"]'); 23 | lightbox.classList.add('is-open'); 24 | document.body.classList.add('is-lightbox-opened'); 25 | }); 26 | }); 27 | Array.prototype.forEach.call(lightboxes, function (lightboxElem) { 28 | lightboxElem.addEventListener('click', function () { 29 | lightboxElem.classList.remove('is-open'); 30 | document.body.classList.remove('is-lightbox-opened'); 31 | }) 32 | }) 33 | }); 34 | })(); 35 | 36 | // prebuildバナー 37 | (function() { 38 | window.addEventListener("load", function () { 39 | const banner = document.querySelector('.js-prebuild'); 40 | const toggleBtn = document.querySelector('.js-prebuild-toggle'); 41 | // バナーが存在するときはトグルで最小化できる 42 | if (banner) { 43 | toggleBtn.addEventListener('click', function(){ 44 | banner.classList.toggle('is-minimize'); 45 | }); 46 | } 47 | }); 48 | }()); 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tokusetsu4", 3 | "version": "1.0.0", 4 | "description": "The fastest way to make doujin landing page", 5 | "author": "sanographix", 6 | "license": "MIT", 7 | "repository": "https://github.com/sanographix/tokusetsu4", 8 | "scripts": { 9 | "prestart": "npm run build", 10 | "start": "npm-run-all -p watch server", 11 | "scss": "sass src/scss/style.scss build/_src/style.css --style compressed", 12 | "autoprefixer": "postcss --use autoprefixer -r build/_src/style.css", 13 | "ejs": "ejs-cli --base-dir src/templates/pages/ --file '**/**.ejs' --out build/", 14 | "server": "browser-sync start -c bs-config.js", 15 | "clean": "rimraf build/_src/*", 16 | "build": "npm run clean & mkdirp build/_src & npm-run-all -p build:* & npm run ejs", 17 | "build:css": "npm-run-all scss autoprefixer", 18 | "build:js_preview": "uglifyjs src/js/preview/* --comments some --compress -o build/_src/preview.js", 19 | "build:js_index": "uglifyjs src/js/index/* --comments some --compress -o build/_src/index.js", 20 | "build:js_i18n": "uglifyjs src/js/i18n/* --comments some --compress -o build/_src/i18n-language.js", 21 | "watch": "npm-run-all -p watch:*", 22 | "watch:css": "onchange 'src/scss/' -- npm run build:css", 23 | "watch:ejs": "onchange 'src/templates/' -- npm run ejs", 24 | "watch:js": "onchange 'src/js/' -- npm-run-all build:js_preview build:js_index" 25 | }, 26 | "devDependencies": { 27 | "autoprefixer": "^10.4.8", 28 | "browser-sync": "^2.27.10", 29 | "chokidar-cli": "^3.0.0", 30 | "ejs-cli": "^2.2.3", 31 | "mkdirp": "^1.0.4", 32 | "normalize.css": "^8.0.1", 33 | "npm-run-all": "^4.1.5", 34 | "onchange": "^7.1.0", 35 | "postcss-cli": "^10.0.0", 36 | "rimraf": "^3.0.2", 37 | "sass": "^1.54.4", 38 | "uglify-es": "^3.3.9" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/scss/component/_setup.scss: -------------------------------------------------------------------------------- 1 | .setup { 2 | min-height: 100vh; 3 | display: flex; 4 | align-items: center; 5 | justify-content: center; 6 | } 7 | .setup-inner { 8 | width: var(--col-width); 9 | max-width: var(--col-width-sm); 10 | margin: auto; 11 | } 12 | .setup-icon { 13 | svg { 14 | fill: var(--color-primary); 15 | } 16 | } 17 | .setup-header { 18 | margin-bottom: var(--space-8); 19 | text-align: center; 20 | h1 { 21 | font-size: var(--font-size-600); 22 | margin: 0 0 var(--space-3); 23 | line-height: var(--line-height-sm); 24 | } 25 | } 26 | .setup-content { 27 | display: grid; 28 | grid-template-columns: auto 1fr; 29 | gap: var(--space-5) var(--space-3); 30 | } 31 | .setup-step-number { 32 | font-size: var(--font-size-200); 33 | line-height: var(--line-height-sm); 34 | color: var(--color-text-highlight); 35 | } 36 | .setup-step-content { 37 | h2 { 38 | margin: 0 0 var(--space-3); 39 | font-size: var(--font-size-200); 40 | line-height: var(--line-height-sm); 41 | } 42 | p { 43 | font-size: var(--font-size-85); 44 | color: var(--color-text-secondary); 45 | } 46 | } 47 | 48 | .setup-footer { 49 | margin-top: var(--space-8); 50 | text-align: center; 51 | .setup-footer-logo { 52 | a { 53 | color: inherit; 54 | } 55 | svg { 56 | opacity: .5; 57 | width: 160px; 58 | fill: currentColor; 59 | path, 60 | polygon { 61 | fill: currentColor; 62 | } 63 | } 64 | a:hover { 65 | svg { 66 | opacity: 1; 67 | } 68 | } 69 | } 70 | .setup-footer-address { 71 | a { 72 | color: var(--color-text-secondary); 73 | text-decoration: none; 74 | font-size: var(--font-size-75); 75 | font-style: normal; 76 | &:hover { 77 | color: var(--color-text); 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/js/i18n/i18n-language.js: -------------------------------------------------------------------------------- 1 | /************************** 2 | * i18n-language.js 3 | * Write by Shin Hyun (kyaryunha) 4 | * Github: https://github.com/kyaryunha 5 | **************************/ 6 | (function () { 7 | let style = document.createElement('style'); 8 | style.innerHTML = ".unselect-language{display: none;}"; 9 | document.getElementsByTagName('head')[0].appendChild(style); 10 | function setLanguage(currentLanguage) { 11 | let notCurrentTagNames = document.querySelectorAll("[data-lang]"); 12 | notCurrentTagNames.forEach(function (tag) { 13 | if ( !tag.classList.contains("unselect-language")) { 14 | tag.classList.add("unselect-language"); 15 | } 16 | }); 17 | let currentTagNames = document.querySelectorAll(`[data-lang="${currentLanguage}"]`); 18 | currentTagNames.forEach(function (tag) { 19 | if ( tag.classList.contains("unselect-language")) { 20 | tag.classList.remove("unselect-language"); 21 | } 22 | }); 23 | let selectLanguage = document.getElementById("change-language"); 24 | selectLanguage.value = currentLanguage; 25 | } 26 | function changeLanguage(){ 27 | let selectLanguage = document.getElementById("change-language"); 28 | let selectLang = selectLanguage.options[selectLanguage.selectedIndex].value; 29 | localStorage.setItem('lang',selectLang); 30 | setLanguage(selectLang); 31 | } 32 | function getLanguage(){ 33 | let language = window.navigator.userLanguage || window.navigator.language; 34 | let lang = language.toLowerCase(); 35 | let localLang = null; 36 | try { 37 | localLang = localStorage.getItem('lang'); 38 | } catch (e) {} 39 | if(localLang !== null) lang = localLang; 40 | let isExist = document.querySelectorAll(`[data-lang="${lang}"]`); 41 | if (isExist.length === 0) { 42 | lang = "en"; 43 | } 44 | return lang; 45 | } 46 | document.getElementById("change-language").addEventListener("change", function (e) { 47 | changeLanguage(); 48 | }); 49 | try{ 50 | setLanguage(getLanguage()); 51 | } 52 | catch (e) {} 53 | })(); 54 | -------------------------------------------------------------------------------- /src/scss/component/_prebuild-banner.scss: -------------------------------------------------------------------------------- 1 | @use "../global" as g; 2 | 3 | .prebuild-banner { 4 | position: fixed; 5 | align-items: center; 6 | bottom: 0; 7 | color: var(--color-text-white); 8 | background: var(--color-service); 9 | width: 100%; 10 | border-radius: var(--border-radius-base) var(--border-radius-base) 0 0; 11 | box-shadow: 0 var(--space-3) var(--space-5) 0 rgba(0,0,0,0.08); 12 | animation: show-banner 1s both; 13 | overflow: hidden; 14 | } 15 | .prebuild-toggle { 16 | display: block; 17 | width: 100%; 18 | background-color: transparent; 19 | border: none; 20 | color: var(--color-text-white); 21 | padding: var(--space-2) var(--space-6); 22 | transition: background .25s; 23 | &:hover { 24 | background: rgba(0,0,0,.16); 25 | } 26 | } 27 | .prebuild-container { 28 | display: flex; 29 | flex-direction: column; 30 | align-items: center; 31 | gap: var(--space-4); 32 | padding: var(--space-2) var(--space-6) var(--space-6); 33 | transition: all .25s; 34 | @media #{g.$mq-md} { 35 | flex-direction: row; 36 | } 37 | // 最小化 38 | .is-minimize & { 39 | height: 0; 40 | padding-top: 0; 41 | padding-bottom: 0; 42 | overflow: hidden; 43 | } 44 | h1 { 45 | margin: 0 0 var(--space-3); 46 | line-height: var(--line-height-xs); 47 | } 48 | p { 49 | margin: var(--space-3) 0 0; 50 | } 51 | .prebuild-action { 52 | margin-left: auto; 53 | } 54 | .prebuild-download { 55 | background-color: var(--color-bg-white); 56 | color: var(--color-service); 57 | display: inline-block; 58 | border-radius: var(--border-radius-rounded); 59 | padding: var(--space-3) var(--space-4); 60 | text-decoration: none; 61 | min-width: 8em; 62 | text-align: center; 63 | white-space: nowrap; 64 | } 65 | @keyframes show-banner { 66 | 0% { 67 | transform:translate(0,2em); 68 | opacity:0; 69 | } 70 | 50% { 71 | transform:translate(0,2em); 72 | opacity:0; 73 | } 74 | 100% { 75 | transform:translate(0,0); 76 | opacity:1; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/scss/component/_footer.scss: -------------------------------------------------------------------------------- 1 | @use "../global" as g; 2 | 3 | .footer { 4 | margin: var(--space-7) auto 0; 5 | border-top: 1px solid var(--color-border); 6 | padding-top: var(--space-4); 7 | } 8 | .footer-wrapper { 9 | display: flex; 10 | justify-content: space-between; 11 | gap: var(--space-4); 12 | color: var(--color-text-secondary); 13 | flex-direction: column; 14 | @media #{g.$mq-md} { 15 | flex-direction: row; 16 | align-items: center; 17 | } 18 | } 19 | .footer-content { 20 | line-height: var(--line-height-sm); 21 | text-align: center; 22 | @media #{g.$mq-md} { 23 | text-align: left; 24 | } 25 | } 26 | .footer-workTitle { 27 | font-weight: bold; 28 | font-size: var(--font-size-75); 29 | text-decoration: none; 30 | color: var(--color-text-secondary); 31 | } 32 | .footer-text { 33 | margin: 0; 34 | font-size: var(--font-size-50); 35 | } 36 | .theme-info { 37 | display: flex; 38 | align-items: center; 39 | flex-shrink: 0; 40 | gap: var(--space-3); 41 | justify-content: space-between; 42 | } 43 | .theme-info-label { 44 | font-size: var(--font-size-50); 45 | @media #{g.$mq-md} { 46 | text-align: right; 47 | } 48 | p { 49 | margin: 0; 50 | } 51 | a { 52 | font-weight: bold; 53 | text-decoration: none; 54 | color: var(--color-text-secondary); 55 | } 56 | } 57 | .footer-tokusetsu-logo { 58 | svg { 59 | width: 90px; 60 | height: 10px; 61 | fill: currentColor; 62 | display: inline-block; 63 | path, 64 | polygon { 65 | fill: currentColor; 66 | } 67 | } 68 | } 69 | .theme-info-install { 70 | flex-shrink: 0; 71 | } 72 | .install-btn { 73 | display: inline-block; 74 | padding: var(--space-2) var(--space-3); 75 | line-height: var(--line-height-sm); 76 | font-family: inherit; 77 | font-size: var(--font-size-50); 78 | letter-spacing: var(--letter-spacing-2); 79 | text-decoration: none; 80 | text-align: center; 81 | transition: all .25s; 82 | border: 0; 83 | cursor: pointer; 84 | box-shadow: inset 0 0 0 1px var(--color-text-secondary); 85 | color: var(--color-text-secondary); 86 | &:hover { 87 | color: var(--color-text-invert); 88 | background-color: var(--color-text-secondary); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/991e760c1c6d50fdda246e0178b9c58b06770b90/Node.gitignore 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | .pnpm-debug.log* 11 | 12 | # Diagnostic reports (https://nodejs.org/api/report.html) 13 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 14 | 15 | # Runtime data 16 | pids 17 | *.pid 18 | *.seed 19 | *.pid.lock 20 | 21 | # Directory for instrumented libs generated by jscoverage/JSCover 22 | lib-cov 23 | 24 | # Coverage directory used by tools like istanbul 25 | coverage 26 | *.lcov 27 | 28 | # nyc test coverage 29 | .nyc_output 30 | 31 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 32 | .grunt 33 | 34 | # Bower dependency directory (https://bower.io/) 35 | bower_components 36 | 37 | # node-waf configuration 38 | .lock-wscript 39 | 40 | # Compiled binary addons (https://nodejs.org/api/addons.html) 41 | build/Release 42 | 43 | # Dependency directories 44 | node_modules/ 45 | jspm_packages/ 46 | 47 | # Snowpack dependency directory (https://snowpack.dev/) 48 | web_modules/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Microbundle cache 60 | .rpt2_cache/ 61 | .rts2_cache_cjs/ 62 | .rts2_cache_es/ 63 | .rts2_cache_umd/ 64 | 65 | # Optional REPL history 66 | .node_repl_history 67 | 68 | # Output of 'npm pack' 69 | *.tgz 70 | 71 | # Yarn Integrity file 72 | .yarn-integrity 73 | 74 | # dotenv environment variables file 75 | .env 76 | .env.test 77 | .env.production 78 | 79 | # parcel-bundler cache (https://parceljs.org/) 80 | .cache 81 | .parcel-cache 82 | 83 | # Next.js build output 84 | .next 85 | out 86 | 87 | # Nuxt.js build / generate output 88 | .nuxt 89 | dist 90 | 91 | # Gatsby files 92 | .cache/ 93 | # Comment in the public line in if your project uses Gatsby and not Next.js 94 | # https://nextjs.org/blog/next-9-1#public-directory-support 95 | # public 96 | 97 | # vuepress build output 98 | .vuepress/dist 99 | 100 | # Serverless directories 101 | .serverless/ 102 | 103 | # FuseBox cache 104 | .fusebox/ 105 | 106 | # DynamoDB Local files 107 | .dynamodb/ 108 | 109 | # TernJS port file 110 | .tern-port 111 | 112 | # Stores VSCode versions used for testing VSCode extensions 113 | .vscode-test 114 | 115 | # yarn v2 116 | .yarn/cache 117 | .yarn/unplugged 118 | .yarn/build-state.yml 119 | .yarn/install-state.gz 120 | .pnp.* 121 | 122 | # Ignore the build directory 123 | build/ 124 | -------------------------------------------------------------------------------- /src/templates/pages/index.ejs: -------------------------------------------------------------------------------- 1 | <% pageId = "setup"; %> 2 | <%- include('../_partial/_header') %> 3 | 4 |
5 |
6 |
7 |
8 | 9 |
10 |

Set up Tokusetsu 4

11 | 12 | 20 | 21 |

Tokusetsu 4 へようこそ。セットアップをはじめましょう!

22 |

Welcome to Tokusetsu 4. Let's start the setup!

23 |
24 |
25 |
1
26 |
27 | 28 |

現在のURLがそのまま本番サイトのURLになります。

29 |

The current URL will be the URL of the production site as it is.

30 | 31 | 現在のURL 32 | Current URL 33 | : 34 | 35 |

URL変更は今のうちに済ませておきましょう。この画面より後にURLを変更すると、再セットアップが必要になります。

36 |

The URL change should be done now. If you change the URL after this screen, you will need to re-set up.

37 | 38 |

Netlifyの場合「Site settings」でURLを変更できます。

39 |

For Netlify, you can change the URL in "Site settings".

40 | 41 |
42 |
2
43 |
44 | 45 |

準備ができたらセットアップをはじめましょう。

46 |

When you are ready, start the setup.

47 | 48 | Set up 49 |
50 |
51 | 59 |
60 |
61 | 62 | 65 | 66 | <%- include('../_partial/_footer') %> 67 | -------------------------------------------------------------------------------- /src/templates/_partial/_logo.ejs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/scss/global/_variable.scss: -------------------------------------------------------------------------------- 1 | :root{ 2 | // Typography 3 | --font: 'DM Sans', -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 4 | --font-size-50: 12px; 5 | --font-size-75: 14px; 6 | --font-size-100: 17px; 7 | --font-size-200: 20px; 8 | --font-size-300: 24px; 9 | --font-size-400: 32px; 10 | --font-size-500: 40px; 11 | --font-size-600: 48px; 12 | --font-size-700: 56px; 13 | --font-size-800: 64px; 14 | --font-size-900: 72px; 15 | --font-size-title: 120px; 16 | --line-height-xs: 1; 17 | --line-height-sm: 1.25; 18 | --line-height-base: 1.6; 19 | --line-height-lg: 1.75; 20 | --letter-spacing-200: .025em; 21 | --letter-spacing-300: .1em; 22 | --letter-spacing-400: .25em; 23 | 24 | // Spacing 25 | --space-1: 4px; 26 | --space-2: 8px; 27 | --space-3: 16px; 28 | --space-4: 24px; 29 | --space-5: 32px; 30 | --space-6: 40px; 31 | --space-7: 48px; 32 | --space-8: 64px; 33 | --space-9: 80px; 34 | 35 | // Column width 36 | --col-width: 90%; 37 | --col-width-sm: 512px; 38 | --col-width-md: 1080px; 39 | --col-width-lg: 1280px; 40 | --col-width-xl: 1400px; 41 | --col-width-2xl: 1600px; 42 | 43 | --col-space: 5vw; 44 | 45 | --border-radius-sm: 6px; 46 | --border-radius-base: 16px; 47 | --border-radius-rounded: 50em; //充分大きな値を決め打ちで入れる 48 | 49 | // z-index 50 | --z-index-bg: -1; 51 | --z-index-base: 1; 52 | --z-sticky: 9; 53 | --z-index-modal: 10; 54 | 55 | // Color 56 | // Global tokens 57 | --color-white: #fff; 58 | --color-ivory: #F0EDEA; 59 | --color-ivory-darken: #e1ded9; 60 | --color-red: #F70138; 61 | --color-turquoise: #00D0DD; 62 | --color-black: #000; 63 | --color-gray-100: #111111; 64 | --color-gray-200: #222222; 65 | --color-gray-300: #333333; 66 | --color-gray-400: #444444; 67 | --color-gray-800: #888888; 68 | --color-gray-900: #dddddd; 69 | --color-primary: var(--color-turquoise); // configシートで変えられる 70 | --color-service: #6107aa; 71 | --color-white-transparent-60: rgba(255,255,255,.6); 72 | --color-black-transparent-60: rgba(0,0,0,.6); 73 | --color-white-transparent: rgba(255,255,255,.16); // 背景の上に薄い色を重ねたいとき 74 | --color-black-transparent: rgba(0,0,0,.16); // 背景の上に薄い色を重ねたいとき 75 | --color-black-blur: rgba(0,0,0,.75); 76 | 77 | --color-tw: #000000; 78 | --color-fb: #1877F2; 79 | 80 | // Alias tokens 81 | --color-bg: var(--color-gray-100); 82 | --color-bg-secondary: var(--color-gray-200); 83 | --color-bg-content: var(--color-gray-200); 84 | --color-bg-white: var(--color-white); 85 | --color-bg-white-secondary: var(--color-gray-900); 86 | --color-text: var(--color-white); 87 | --color-text-invert: var(--color-black); 88 | --color-text-secondary: var(--color-white-transparent-60); 89 | --color-text-highlight: var(--color-primary); 90 | --color-text-white: var(--color-white); 91 | 92 | --color-btn-primary-bg: var(--color-primary); 93 | --color-btn-primary-text: var(--color-text); 94 | --color-btn-primary-ghost-border: var(--color-primary); 95 | --color-btn-primary-ghost-text: var(--color-primary); 96 | --color-btn-secondary: var(--color-white-transparent); 97 | --color-btn-tw: var(--color-tw); 98 | --color-btn-fb: var(--color-fb); 99 | 100 | --color-border: var(--color-white-transparent); 101 | --color-border-highlight: var(--color-primary); 102 | --color-blur: var(--color-black-blur); 103 | } 104 | 105 | :root[data-theme='Light'] { 106 | --color-bg-secondary: var(--color-ivory-darken); 107 | --color-text: var(--color-gray-200); 108 | --color-text-secondary: var(--color-black-transparent-60); 109 | --color-text-invert: var(--color-white); 110 | --color-border: var(--color-black-transparent); 111 | --color-btn-secondary: var(--color-black-transparent); 112 | --color-blur: var(--color-white-transparent); 113 | } 114 | 115 | // media queries 116 | $mq-sm: "(min-width: 576px)"; 117 | $mq-md: "(min-width: 768px)"; 118 | $mq-lg: "(min-width: 992px)"; 119 | $mq-xl: "(min-width: 1280px)"; 120 | $mq-xxl: "(min-width: 1600px)"; 121 | 122 | @mixin container() { 123 | @media #{$mq-md} { 124 | margin-left: auto; 125 | margin-right: auto; 126 | width: var(--col-width); 127 | max-width: var(--col-width-lg); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/js/preview/csv.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"function"==typeof define&&define.amd?define([],e):"object"==typeof module&&module.exports?module.exports=e():t.CSV=e()}(this,function(){"use strict";function t(t){var e=typeof t;return"function"===e||"object"===e&&!!t}function e(t){return"string"==typeof t}function n(t){return!isNaN(+t)}function i(t){return 0==t||1==t}function r(t){return null==t}function o(t){return null!=t}function c(t,e){return o(t)?t:e}function u(t,e){for(var n=0,i=t.length;i>n&&e(t[n],n)!==!1;n+=1);}function s(t){return t.replace(/"/g,'\\"')}function a(t){return"attrs["+t+"]"}function l(t,e){return n(t)?"Number("+a(e)+")":i(t)?"Boolean("+a(e)+" == true)":"String("+a(e)+")"}function f(t,n,i,r){var o=[];return 3==arguments.length?(n?g(n)?u(i,function(i,r){e(n[r])?n[r]=n[r].toLowerCase():t[n[r]]=n[r],o.push("deserialize[cast["+r+"]]("+a(r)+")")}):u(i,function(t,e){o.push(l(t,e))}):u(i,function(t,e){o.push(a(e))}),o="return ["+o.join(",")+"]"):(n?g(n)?u(i,function(i,c){e(n[c])?n[c]=n[c].toLowerCase():t[n[c]]=n[c],o.push('"'+s(r[c])+'": deserialize[cast['+c+"]]("+a(c)+")")}):u(i,function(t,e){o.push('"'+s(r[e])+'": '+l(t,e))}):u(i,function(t,e){o.push('"'+s(r[e])+'": '+a(e))}),o="return {"+o.join(",")+"}"),Function("attrs","deserialize","cast",o)}function h(t,e){var n,i=0;return u(e,function(e){var r,o=e;-1!=p.indexOf(e)&&(o="\\"+o),r=t.match(RegExp(o,"g")),r&&r.length>i&&(i=r.length,n=e)}),n||e[0]}var p=["|","^"],d=[",",";"," ","|","^"],m=["\r\n","\r","\n"],g=Array.isArray||function(t){return"[object Array]"===toString.call(t)},y=function(){function n(t,n){if(n||(n={}),g(t))this.mode="encode";else{if(!e(t))throw Error("Incompatible format!");this.mode="parse"}this.data=t,this.options={header:c(n.header,!1),cast:c(n.cast,!0)};var i=n.lineDelimiter||n.line,r=n.cellDelimiter||n.delimiter;this.isParser()?(this.options.lineDelimiter=i||h(this.data,m),this.options.cellDelimiter=r||h(this.data,d),this.data=o(this.data,this.options.lineDelimiter)):this.isEncoder()&&(this.options.lineDelimiter=i||"\r\n",this.options.cellDelimiter=r||",")}function i(t,e,n,i,r){t(new e(n,i,r))}function o(t,e){return t.slice(-e.length)!=e&&(t+=e),t}function s(n){return g(n)?"array":t(n)?"object":e(n)?"string":r(n)?"null":"primitive"}return n.prototype.set=function(t,e){return this.options[t]=e},n.prototype.isParser=function(){return"parse"==this.mode},n.prototype.isEncoder=function(){return"encode"==this.mode},n.prototype.parse=function(t){function e(){s={escaped:!1,quote:!1,cell:!0}}function n(){m.cell=""}function r(){m.line=[]}function o(t){m.line.push(s.escaped?t.slice(1,-1).replace(/""/g,'"'):t),n(),e()}function c(t){o(t.slice(0,1-p.lineDelimiter.length))}function u(){d?g(d)?(a=f(y,p.cast,m.line,d),(u=function(){i(t,a,m.line,y,p.cast)})()):d=m.line:(a||(a=f(y,p.cast,m.line)),(u=function(){i(t,a,m.line,y,p.cast)})())}if("parse"==this.mode){if(0===this.data.trim().length)return[];var s,a,l,h=this.data,p=this.options,d=p.header,m={cell:"",line:[]},y=this.deserialize;t||(l=[],t=function(t){l.push(t)}),1==p.lineDelimiter.length&&(c=o);var v,A,D,b=h.length,j=p.cellDelimiter.charCodeAt(0),w=p.lineDelimiter.charCodeAt(p.lineDelimiter.length-1);for(e(),v=0,A=0;b>v;v++)D=h.charCodeAt(v),s.cell&&(s.cell=!1,34==D)?s.escaped=!0:s.escaped&&34==D?s.quote=!s.quote:(s.escaped&&s.quote||!s.escaped)&&(D==j?(o(m.cell+h.slice(A,v)),A=v+1):D==w&&(c(m.cell+h.slice(A,v)),A=v+1,(m.line.length>1||""!==m.line[0])&&u(),r()));return l?l:this}},n.prototype.deserialize={string:function(t){return t+""},number:function(t){return+t},"boolean":function(t){return!!t}},n.prototype.serialize={object:function(t){var e=this,n=Object.keys(t),i=Array(n.length);return u(n,function(n,r){i[r]=e[s(t[n])](t[n])}),i},array:function(t){var e=this,n=Array(t.length);return u(t,function(t,i){n[i]=e[s(t)](t)}),n},string:function(t){return'"'+(t+"").replace(/"/g,'""')+'"'},"null":function(){return""},primitive:function(t){return t}},n.prototype.encode=function(t){function n(t){return t.join(c.cellDelimiter)}if("encode"==this.mode){if(0==this.data.length)return"";var i,r,o=this.data,c=this.options,a=c.header,l=o[0],f=this.serialize,h=0;t||(r=Array(o.length),t=function(t,e){r[e+h]=t}),a&&(g(a)||(i=Object.keys(l),a=i),t(n(f.array(a)),0),h=1);var p,d=s(l);return"array"==d?(g(c.cast)?(p=Array(c.cast.length),u(c.cast,function(t,n){e(t)?p[n]=t.toLowerCase():(p[n]=t,f[t]=t)})):(p=Array(l.length),u(l,function(t,e){p[e]=s(t)})),u(o,function(e,i){var r=Array(p.length);u(e,function(t,e){r[e]=f[p[e]](t)}),t(n(r),i)})):"object"==d&&(i=Object.keys(l),g(c.cast)?(p=Array(c.cast.length),u(c.cast,function(t,n){e(t)?p[n]=t.toLowerCase():(p[n]=t,f[t]=t)})):(p=Array(i.length),u(i,function(t,e){p[e]=s(l[t])})),u(o,function(e,r){var o=Array(i.length);u(i,function(t,n){o[n]=f[p[n]](e[t])}),t(n(o),r)})),r?r.join(c.lineDelimiter):this}},n.prototype.forEach=function(t){return this[this.mode](t)},n}();return y.parse=function(t,e){return new y(t,e).parse()},y.encode=function(t,e){return new y(t,e).encode()},y.forEach=function(t,e,n){return 2==arguments.length&&(n=e),new y(t,e).forEach(n)},y}); -------------------------------------------------------------------------------- /src/scss/foundation/_normalize.scss: -------------------------------------------------------------------------------- 1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in iOS. 9 | */ 10 | 11 | html { 12 | line-height: 1.15; /* 1 */ 13 | -webkit-text-size-adjust: 100%; /* 2 */ 14 | } 15 | 16 | /* Sections 17 | ========================================================================== */ 18 | 19 | /** 20 | * Remove the margin in all browsers. 21 | */ 22 | 23 | body { 24 | margin: 0; 25 | } 26 | 27 | /** 28 | * Render the `main` element consistently in IE. 29 | */ 30 | 31 | main { 32 | display: block; 33 | } 34 | 35 | /** 36 | * Correct the font size and margin on `h1` elements within `section` and 37 | * `article` contexts in Chrome, Firefox, and Safari. 38 | */ 39 | 40 | h1 { 41 | font-size: 2em; 42 | margin: 0.67em 0; 43 | } 44 | 45 | /* Grouping content 46 | ========================================================================== */ 47 | 48 | /** 49 | * 1. Add the correct box sizing in Firefox. 50 | * 2. Show the overflow in Edge and IE. 51 | */ 52 | 53 | hr { 54 | box-sizing: content-box; /* 1 */ 55 | height: 0; /* 1 */ 56 | overflow: visible; /* 2 */ 57 | } 58 | 59 | /** 60 | * 1. Correct the inheritance and scaling of font size in all browsers. 61 | * 2. Correct the odd `em` font sizing in all browsers. 62 | */ 63 | 64 | pre { 65 | font-family: monospace, monospace; /* 1 */ 66 | font-size: 1em; /* 2 */ 67 | } 68 | 69 | /* Text-level semantics 70 | ========================================================================== */ 71 | 72 | /** 73 | * Remove the gray background on active links in IE 10. 74 | */ 75 | 76 | a { 77 | background-color: transparent; 78 | } 79 | 80 | /** 81 | * 1. Remove the bottom border in Chrome 57- 82 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 83 | */ 84 | 85 | abbr[title] { 86 | border-bottom: none; /* 1 */ 87 | text-decoration: underline; /* 2 */ 88 | text-decoration: underline dotted; /* 2 */ 89 | } 90 | 91 | /** 92 | * Add the correct font weight in Chrome, Edge, and Safari. 93 | */ 94 | 95 | b, 96 | strong { 97 | font-weight: bolder; 98 | } 99 | 100 | /** 101 | * 1. Correct the inheritance and scaling of font size in all browsers. 102 | * 2. Correct the odd `em` font sizing in all browsers. 103 | */ 104 | 105 | code, 106 | kbd, 107 | samp { 108 | font-family: monospace, monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /** 113 | * Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /** 121 | * Prevent `sub` and `sup` elements from affecting the line height in 122 | * all browsers. 123 | */ 124 | 125 | sub, 126 | sup { 127 | font-size: 75%; 128 | line-height: 0; 129 | position: relative; 130 | vertical-align: baseline; 131 | } 132 | 133 | sub { 134 | bottom: -0.25em; 135 | } 136 | 137 | sup { 138 | top: -0.5em; 139 | } 140 | 141 | /* Embedded content 142 | ========================================================================== */ 143 | 144 | /** 145 | * Remove the border on images inside links in IE 10. 146 | */ 147 | 148 | img { 149 | border-style: none; 150 | } 151 | 152 | /* Forms 153 | ========================================================================== */ 154 | 155 | /** 156 | * 1. Change the font styles in all browsers. 157 | * 2. Remove the margin in Firefox and Safari. 158 | */ 159 | 160 | button, 161 | input, 162 | optgroup, 163 | select, 164 | textarea { 165 | font-family: inherit; /* 1 */ 166 | font-size: 100%; /* 1 */ 167 | line-height: 1.15; /* 1 */ 168 | margin: 0; /* 2 */ 169 | } 170 | 171 | /** 172 | * Show the overflow in IE. 173 | * 1. Show the overflow in Edge. 174 | */ 175 | 176 | button, 177 | input { /* 1 */ 178 | overflow: visible; 179 | } 180 | 181 | /** 182 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 183 | * 1. Remove the inheritance of text transform in Firefox. 184 | */ 185 | 186 | button, 187 | select { /* 1 */ 188 | text-transform: none; 189 | } 190 | 191 | /** 192 | * Correct the inability to style clickable types in iOS and Safari. 193 | */ 194 | 195 | button, 196 | [type="button"], 197 | [type="reset"], 198 | [type="submit"] { 199 | -webkit-appearance: button; 200 | } 201 | 202 | /** 203 | * Remove the inner border and padding in Firefox. 204 | */ 205 | 206 | button::-moz-focus-inner, 207 | [type="button"]::-moz-focus-inner, 208 | [type="reset"]::-moz-focus-inner, 209 | [type="submit"]::-moz-focus-inner { 210 | border-style: none; 211 | padding: 0; 212 | } 213 | 214 | /** 215 | * Restore the focus styles unset by the previous rule. 216 | */ 217 | 218 | button:-moz-focusring, 219 | [type="button"]:-moz-focusring, 220 | [type="reset"]:-moz-focusring, 221 | [type="submit"]:-moz-focusring { 222 | outline: 1px dotted ButtonText; 223 | } 224 | 225 | /** 226 | * Correct the padding in Firefox. 227 | */ 228 | 229 | fieldset { 230 | padding: 0.35em 0.75em 0.625em; 231 | } 232 | 233 | /** 234 | * 1. Correct the text wrapping in Edge and IE. 235 | * 2. Correct the color inheritance from `fieldset` elements in IE. 236 | * 3. Remove the padding so developers are not caught out when they zero out 237 | * `fieldset` elements in all browsers. 238 | */ 239 | 240 | legend { 241 | box-sizing: border-box; /* 1 */ 242 | color: inherit; /* 2 */ 243 | display: table; /* 1 */ 244 | max-width: 100%; /* 1 */ 245 | padding: 0; /* 3 */ 246 | white-space: normal; /* 1 */ 247 | } 248 | 249 | /** 250 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 251 | */ 252 | 253 | progress { 254 | vertical-align: baseline; 255 | } 256 | 257 | /** 258 | * Remove the default vertical scrollbar in IE 10+. 259 | */ 260 | 261 | textarea { 262 | overflow: auto; 263 | } 264 | 265 | /** 266 | * 1. Add the correct box sizing in IE 10. 267 | * 2. Remove the padding in IE 10. 268 | */ 269 | 270 | [type="checkbox"], 271 | [type="radio"] { 272 | box-sizing: border-box; /* 1 */ 273 | padding: 0; /* 2 */ 274 | } 275 | 276 | /** 277 | * Correct the cursor style of increment and decrement buttons in Chrome. 278 | */ 279 | 280 | [type="number"]::-webkit-inner-spin-button, 281 | [type="number"]::-webkit-outer-spin-button { 282 | height: auto; 283 | } 284 | 285 | /** 286 | * 1. Correct the odd appearance in Chrome and Safari. 287 | * 2. Correct the outline style in Safari. 288 | */ 289 | 290 | [type="search"] { 291 | -webkit-appearance: textfield; /* 1 */ 292 | outline-offset: -2px; /* 2 */ 293 | } 294 | 295 | /** 296 | * Remove the inner padding in Chrome and Safari on macOS. 297 | */ 298 | 299 | [type="search"]::-webkit-search-decoration { 300 | -webkit-appearance: none; 301 | } 302 | 303 | /** 304 | * 1. Correct the inability to style clickable types in iOS and Safari. 305 | * 2. Change font properties to `inherit` in Safari. 306 | */ 307 | 308 | ::-webkit-file-upload-button { 309 | -webkit-appearance: button; /* 1 */ 310 | font: inherit; /* 2 */ 311 | } 312 | 313 | /* Interactive 314 | ========================================================================== */ 315 | 316 | /* 317 | * Add the correct display in Edge, IE 10+, and Firefox. 318 | */ 319 | 320 | details { 321 | display: block; 322 | } 323 | 324 | /* 325 | * Add the correct display in all browsers. 326 | */ 327 | 328 | summary { 329 | display: list-item; 330 | } 331 | 332 | /* Misc 333 | ========================================================================== */ 334 | 335 | /** 336 | * Add the correct display in IE 10+. 337 | */ 338 | 339 | template { 340 | display: none; 341 | } 342 | 343 | /** 344 | * Add the correct display in IE 10. 345 | */ 346 | 347 | [hidden] { 348 | display: none; 349 | } 350 | -------------------------------------------------------------------------------- /src/js/index/vanilla-tilt.min.js: -------------------------------------------------------------------------------- 1 | var VanillaTilt=function(){"use strict";class t{constructor(e,i={}){if(!(e instanceof Node))throw"Can't initialize VanillaTilt because "+e+" is not a Node.";this.width=null,this.height=null,this.clientWidth=null,this.clientHeight=null,this.left=null,this.top=null,this.gammazero=null,this.betazero=null,this.lastgammazero=null,this.lastbetazero=null,this.transitionTimeout=null,this.updateCall=null,this.event=null,this.updateBind=this.update.bind(this),this.resetBind=this.reset.bind(this),this.element=e,this.settings=this.extendSettings(i),this.reverse=this.settings.reverse?-1:1,this.glare=t.isSettingTrue(this.settings.glare),this.glarePrerender=t.isSettingTrue(this.settings["glare-prerender"]),this.fullPageListening=t.isSettingTrue(this.settings["full-page-listening"]),this.gyroscope=t.isSettingTrue(this.settings.gyroscope),this.gyroscopeSamples=this.settings.gyroscopeSamples,this.elementListener=this.getElementListener(),this.glare&&this.prepareGlare(),this.fullPageListening&&this.updateClientSize(),this.addEventListeners(),this.reset(),this.updateInitialPosition()}static isSettingTrue(t){return""===t||!0===t||1===t}getElementListener(){if(this.fullPageListening)return window.document;if("string"==typeof this.settings["mouse-event-element"]){const t=document.querySelector(this.settings["mouse-event-element"]);if(t)return t}return this.settings["mouse-event-element"]instanceof Node?this.settings["mouse-event-element"]:this.element}addEventListeners(){this.onMouseEnterBind=this.onMouseEnter.bind(this),this.onMouseMoveBind=this.onMouseMove.bind(this),this.onMouseLeaveBind=this.onMouseLeave.bind(this),this.onWindowResizeBind=this.onWindowResize.bind(this),this.onDeviceOrientationBind=this.onDeviceOrientation.bind(this),this.elementListener.addEventListener("mouseenter",this.onMouseEnterBind),this.elementListener.addEventListener("mouseleave",this.onMouseLeaveBind),this.elementListener.addEventListener("mousemove",this.onMouseMoveBind),(this.glare||this.fullPageListening)&&window.addEventListener("resize",this.onWindowResizeBind),this.gyroscope&&window.addEventListener("deviceorientation",this.onDeviceOrientationBind)}removeEventListeners(){this.elementListener.removeEventListener("mouseenter",this.onMouseEnterBind),this.elementListener.removeEventListener("mouseleave",this.onMouseLeaveBind),this.elementListener.removeEventListener("mousemove",this.onMouseMoveBind),this.gyroscope&&window.removeEventListener("deviceorientation",this.onDeviceOrientationBind),(this.glare||this.fullPageListening)&&window.removeEventListener("resize",this.onWindowResizeBind)}destroy(){clearTimeout(this.transitionTimeout),null!==this.updateCall&&cancelAnimationFrame(this.updateCall),this.reset(),this.removeEventListeners(),this.element.vanillaTilt=null,delete this.element.vanillaTilt,this.element=null}onDeviceOrientation(t){if(null===t.gamma||null===t.beta)return;this.updateElementPosition(),this.gyroscopeSamples>0&&(this.lastgammazero=this.gammazero,this.lastbetazero=this.betazero,null===this.gammazero?(this.gammazero=t.gamma,this.betazero=t.beta):(this.gammazero=(t.gamma+this.lastgammazero)/2,this.betazero=(t.beta+this.lastbetazero)/2),this.gyroscopeSamples-=1);const e=this.settings.gyroscopeMaxAngleX-this.settings.gyroscopeMinAngleX,i=this.settings.gyroscopeMaxAngleY-this.settings.gyroscopeMinAngleY,s=e/this.width,n=i/this.height,l=(t.gamma-(this.settings.gyroscopeMinAngleX+this.gammazero))/s,a=(t.beta-(this.settings.gyroscopeMinAngleY+this.betazero))/n;null!==this.updateCall&&cancelAnimationFrame(this.updateCall),this.event={clientX:l+this.left,clientY:a+this.top},this.updateCall=requestAnimationFrame(this.updateBind)}onMouseEnter(){this.updateElementPosition(),this.element.style.willChange="transform",this.setTransition()}onMouseMove(t){null!==this.updateCall&&cancelAnimationFrame(this.updateCall),this.event=t,this.updateCall=requestAnimationFrame(this.updateBind)}onMouseLeave(){this.setTransition(),this.settings.reset&&requestAnimationFrame(this.resetBind)}reset(){this.event={clientX:this.left+this.width/2,clientY:this.top+this.height/2},this.element&&this.element.style&&(this.element.style.transform=`perspective(${this.settings.perspective}px) `+"rotateX(0deg) rotateY(0deg) scale3d(1, 1, 1)"),this.resetGlare()}resetGlare(){this.glare&&(this.glareElement.style.transform="rotate(180deg) translate(-50%, -50%)",this.glareElement.style.opacity="0")}updateInitialPosition(){if(0===this.settings.startX&&0===this.settings.startY)return;this.onMouseEnter(),this.fullPageListening?this.event={clientX:(this.settings.startX+this.settings.max)/(2*this.settings.max)*this.clientWidth,clientY:(this.settings.startY+this.settings.max)/(2*this.settings.max)*this.clientHeight}:this.event={clientX:this.left+(this.settings.startX+this.settings.max)/(2*this.settings.max)*this.width,clientY:this.top+(this.settings.startY+this.settings.max)/(2*this.settings.max)*this.height};let t=this.settings.scale;this.settings.scale=1,this.update(),this.settings.scale=t,this.resetGlare()}getValues(){let t,e;return this.fullPageListening?(t=this.event.clientX/this.clientWidth,e=this.event.clientY/this.clientHeight):(t=(this.event.clientX-this.left)/this.width,e=(this.event.clientY-this.top)/this.height),t=Math.min(Math.max(t,0),1),e=Math.min(Math.max(e,0),1),{tiltX:(this.reverse*(this.settings.max-t*this.settings.max*2)).toFixed(2),tiltY:(this.reverse*(e*this.settings.max*2-this.settings.max)).toFixed(2),percentageX:100*t,percentageY:100*e,angle:Math.atan2(this.event.clientX-(this.left+this.width/2),-(this.event.clientY-(this.top+this.height/2)))*(180/Math.PI)}}updateElementPosition(){let t=this.element.getBoundingClientRect();this.width=this.element.offsetWidth,this.height=this.element.offsetHeight,this.left=t.left,this.top=t.top}update(){let t=this.getValues();this.element.style.transform="perspective("+this.settings.perspective+"px) rotateX("+("x"===this.settings.axis?0:t.tiltY)+"deg) rotateY("+("y"===this.settings.axis?0:t.tiltX)+"deg) scale3d("+this.settings.scale+", "+this.settings.scale+", "+this.settings.scale+")",this.glare&&(this.glareElement.style.transform=`rotate(${t.angle}deg) translate(-50%, -50%)`,this.glareElement.style.opacity=`${t.percentageY*this.settings["max-glare"]/100}`),this.element.dispatchEvent(new CustomEvent("tiltChange",{detail:t})),this.updateCall=null}prepareGlare(){if(!this.glarePrerender){const t=document.createElement("div");t.classList.add("js-tilt-glare");const e=document.createElement("div");e.classList.add("js-tilt-glare-inner"),t.appendChild(e),this.element.appendChild(t)}this.glareElementWrapper=this.element.querySelector(".js-tilt-glare"),this.glareElement=this.element.querySelector(".js-tilt-glare-inner"),this.glarePrerender||(Object.assign(this.glareElementWrapper.style,{position:"absolute",top:"0",left:"0",width:"100%",height:"100%",overflow:"hidden","pointer-events":"none"}),Object.assign(this.glareElement.style,{position:"absolute",top:"50%",left:"50%","pointer-events":"none","background-image":"linear-gradient(0deg, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 100%)",transform:"rotate(180deg) translate(-50%, -50%)","transform-origin":"0% 0%",opacity:"0"}),this.updateGlareSize())}updateGlareSize(){if(this.glare){const t=2*(this.element.offsetWidth>this.element.offsetHeight?this.element.offsetWidth:this.element.offsetHeight);Object.assign(this.glareElement.style,{width:`${t}px`,height:`${t}px`})}}updateClientSize(){this.clientWidth=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,this.clientHeight=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight}onWindowResize(){this.updateGlareSize(),this.updateClientSize()}setTransition(){clearTimeout(this.transitionTimeout),this.element.style.transition=this.settings.speed+"ms "+this.settings.easing,this.glare&&(this.glareElement.style.transition=`opacity ${this.settings.speed}ms ${this.settings.easing}`),this.transitionTimeout=setTimeout(()=>{this.element.style.transition="",this.glare&&(this.glareElement.style.transition="")},this.settings.speed)}extendSettings(t){let e={reverse:!1,max:15,startX:0,startY:0,perspective:1e3,easing:"cubic-bezier(.03,.98,.52,.99)",scale:1,speed:300,transition:!0,axis:null,glare:!1,"max-glare":1,"glare-prerender":!1,"full-page-listening":!1,"mouse-event-element":null,reset:!0,gyroscope:!0,gyroscopeMinAngleX:-45,gyroscopeMaxAngleX:45,gyroscopeMinAngleY:-45,gyroscopeMaxAngleY:45,gyroscopeSamples:10},i={};for(var s in e)if(s in t)i[s]=t[s];else if(this.element.hasAttribute("data-tilt-"+s)){let t=this.element.getAttribute("data-tilt-"+s);try{i[s]=JSON.parse(t)}catch(e){i[s]=t}}else i[s]=e[s];return i}static init(e,i){e instanceof Node&&(e=[e]),e instanceof NodeList&&(e=[].slice.call(e)),e instanceof Array&&e.forEach(e=>{"vanillaTilt"in e||(e.vanillaTilt=new t(e,i))})}}return"undefined"!=typeof document&&(window.VanillaTilt=t,t.init(document.querySelectorAll("[data-tilt]"))),t}(); -------------------------------------------------------------------------------- /src/templates/pages/preview.ejs: -------------------------------------------------------------------------------- 1 | <% pageId = "preview"; %> <%- include('../_partial/_header') %> 2 | 3 |
4 | 5 |
6 | 7 |
8 |
9 |
10 |
11 |
12 |
13 |
20 | Album Art 21 |
22 |
23 |
24 | NOW PRINTING 25 |
26 |
27 |
28 |

Header Title

29 |

Organization Name

30 |
31 |
Specification
32 |
33 | Specification 34 |
35 |
Release Date
36 |
Release Date
37 |
Location
38 |
Location
39 |
Price
40 |
Price
41 |
Hashtag
42 |
43 | #hashtag 50 |
51 |
52 |
53 |
54 |
55 |

Store

56 |
57 | Store 64 |
65 |
66 | 119 | 120 |
121 | 131 |
132 | 143 |
144 |
145 | 146 |
147 |
148 |
149 |

About

150 |
151 |
152 |
153 |

About

154 |
155 |
156 |
157 |
158 | 191 |
192 |
193 |
194 |

Tracklist

195 |
196 |
197 |
198 |
199 |
200 |

Track name

201 |
202 | Track description 203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |

Member Heading

213 |
214 |
215 |
216 |
Role
217 |
218 | Member name 219 | 228 |
229 |
230 |
231 |
232 |
233 |
234 | 241 | 251 |
252 | 297 |
298 |
299 | 300 | 330 | 331 | <%- include('../_partial/_footer') %> 332 | -------------------------------------------------------------------------------- /src/js/preview/preview.js: -------------------------------------------------------------------------------- 1 | /*@license 2 | * 3 | * Tokusetsu 4: 4 | * licenses: MIT 5 | * Copyright (c) 2022 sanographix 6 | * https://github.com/sanographix/tokusetsu4 7 | * CSV.js: 8 | * licenses: MIT 9 | * Copyright (c) 2014 Kash Nouroozi 10 | * https://github.com/knrz/CSV.js 11 | * vanilla-tilt.js: 12 | * licenses: MIT 13 | * Copyright (c) 2017 Șandor Sergiu 14 | * https://github.com/micku7zu/vanilla-tilt.js 15 | * i18n-language.js: 16 | * licenses: MIT 17 | * Copyright (c) 2020 Shin Hyun 18 | * https://github.com/kyaryunha/i18n-language.js 19 | */ 20 | 21 | // watchされているので保存したらビルドされる 22 | function csv_data(dataPath) { 23 | const request = new XMLHttpRequest(); 24 | request.addEventListener("load", (event) => { 25 | // ロードさせ実行 26 | const response = event.target.responseText; // 受け取ったテキストを返す 27 | csv_array(response); //csv_arrayの関数を実行 28 | }); 29 | request.open("GET", dataPath, true); // csvのパスを指定 30 | request.send(); 31 | } 32 | csv_data("config.csv"); // csvのパス 33 | 34 | function csv_array(data) { 35 | const array = new CSV(data, { 36 | header: [ 37 | "option", 38 | "value1", 39 | "value2", 40 | "value3", 41 | "value4", 42 | "value5", 43 | "required", 44 | "description", 45 | ], 46 | cast: false, 47 | }).parse(); //配列を用意 48 | 49 | console.log(array); 50 | 51 | // ここからサイトの設定項目を組み立てる 52 | 53 | ///////////////////////////////////// 54 | // -Basics- 55 | 56 | // Site Title 57 | const optWorkTitle = array.filter((value) => value.option === "Title"); 58 | const optOrganization = array.filter( 59 | (value) => value.option === "Organization Name" 60 | ); 61 | 62 | const valWorkTitle = optWorkTitle[0].value1; 63 | var valOrganization = optOrganization[0].value1; 64 | 65 | // エンコードされたイベントタイトル(Googleカレンダー追加ボタンに使う) 66 | const encodedWorkTitle = encodeURIComponent(valWorkTitle); 67 | 68 | const siteTitle = new String(valWorkTitle + " | " + valOrganization); 69 | // エンコードされたタイトル(シェアボタンに使う) 70 | const encodedSiteTitle = encodeURIComponent(siteTitle); 71 | 72 | document.title = siteTitle; 73 | 74 | // Site URL (トレイリングスラッシュありに統一してる) 75 | // サブディレクトリも考慮して、location.pathnameの最後のスラッシュを削除 76 | const siteUrl = `${location.protocol}//${location.hostname}${location.pathname.replace(/\/[^/]*$/, '/')}`; 77 | 78 | // Hashtag 79 | const valHashtag = array.filter((value) => value.option === "Hashtag")[0] 80 | .value1; 81 | 82 | // Favicon (option) 83 | try { 84 | const optFavicon = array.filter( 85 | (value) => value.option === "Site Icon (favicon)" 86 | ); 87 | const valFavicon = optFavicon[0].value1; 88 | if (valFavicon != "") { 89 | var favicon = document.createElement("link"); 90 | favicon.rel = "icon"; 91 | favicon.href = valFavicon; 92 | document.head.appendChild(favicon); 93 | } 94 | } catch (error) { 95 | console.error("Error: favicon"); 96 | } 97 | 98 | // Canonical 99 | try { 100 | const domCanonical = document.getElementById("canonical"); 101 | domCanonical.href = siteUrl; 102 | } catch (error) { 103 | console.error("Error: canonical"); 104 | } 105 | 106 | // cover (og-imageの代替になりうるので先に定義しておく) 107 | const optCover = array.filter((value) => value.option === "Cover"); 108 | var valCoverSrc = optCover[0].value1; 109 | 110 | // og-image 111 | const optOgImage = array.filter((value) => value.option === "Share Image"); 112 | var valOgImageSrc = optOgImage[0].value1; 113 | // Share Imageが記入されていればファイル名を指定 114 | // カラだったらカバーを代替画像にする 115 | if (valOgImageSrc != "") { 116 | var valOgImage = valOgImageSrc; 117 | } else { 118 | var valOgImage = valCoverSrc; 119 | } 120 | 121 | // og-description 122 | // About の1行目の値を利用する 123 | const optAbout = array.filter((value) => value.option === "About"); 124 | const valAbout = optAbout[0].value1; 125 | 126 | // OGP 127 | try { 128 | const OGP = [ 129 | { 130 | property: "og:description", 131 | content: valAbout, 132 | }, 133 | { 134 | property: "og:title", 135 | content: siteTitle, 136 | }, 137 | { 138 | property: "og:url", 139 | content: siteUrl, 140 | }, 141 | { 142 | property: "og:image", 143 | content: siteUrl + valOgImage, 144 | }, 145 | { 146 | name: "twitter:title", 147 | content: siteTitle, 148 | }, 149 | { 150 | name: "twitter:description", 151 | content: valAbout, 152 | }, 153 | { 154 | name: "twitter:image", 155 | content: siteUrl + valOgImage, 156 | }, 157 | ]; 158 | for (let i = 0; i < OGP.length; i++) { 159 | const metaTag = document.createElement("meta"); 160 | for (let prop in OGP[i]) { 161 | metaTag.setAttribute(prop, OGP[i][prop]); 162 | } 163 | document.head.appendChild(metaTag); 164 | } 165 | } catch (error) { 166 | console.error("Error: OGP"); 167 | } 168 | 169 | ///////////////////////////////////// 170 | // -Design- 171 | 172 | // Utils 173 | // 文字色(白・黒)を背景色のカラーコードから判定する関数 174 | // Theme, Accent Color で使用 175 | function blackOrWhite(hexcolor) { 176 | var r = parseInt(hexcolor.substr(1, 2), 16); 177 | var g = parseInt(hexcolor.substr(3, 2), 16); 178 | var b = parseInt(hexcolor.substr(5, 2), 16); 179 | return (r * 299 + g * 587 + b * 114) / 1000 < 128 ? "white" : "black"; 180 | } 181 | 182 | // Background Color 183 | try { 184 | var valBackgroundColor = array.filter( 185 | (value) => value.option === "Background Color (Hex)" 186 | )[0].value1; 187 | if (valBackgroundColor != "") { 188 | // 背景色を適用 189 | document.head.insertAdjacentHTML( 190 | "beforeend", 191 | "" 192 | ); 193 | } 194 | } catch (error) { 195 | console.error("Error: background-color"); 196 | } 197 | 198 | // Accent Color 199 | try { 200 | const valAccentColor = array.filter( 201 | (value) => value.option === "Accent Color (Hex)" 202 | )[0].value1; 203 | if (valAccentColor != "") { 204 | // アクセントカラーを適用 205 | document.head.insertAdjacentHTML( 206 | "beforeend", 207 | "" 208 | ); 209 | document.documentElement.setAttribute( 210 | "data-accent-color", 211 | valAccentColor 212 | ); 213 | // metaタグに指定 214 | const domThemeColor = document.getElementById("meta-theme-color"); 215 | domThemeColor.content = valAccentColor; 216 | 217 | const AccentColorText = blackOrWhite(valAccentColor); 218 | switch (AccentColorText) { 219 | case "black": 220 | document.head.insertAdjacentHTML( 221 | "beforeend", 222 | "" 223 | ); 224 | break; 225 | case "white": 226 | document.head.insertAdjacentHTML( 227 | "beforeend", 228 | "" 229 | ); 230 | break; 231 | default: 232 | break; 233 | } 234 | } 235 | } catch (error) { 236 | console.error("Error: accent-color"); 237 | } 238 | 239 | // Background Image 240 | try { 241 | const optBackgroundImage = array.filter( 242 | (value) => value.option === "Background Image" 243 | ); 244 | const valBackgroundImageSrc = optBackgroundImage[0].value1; 245 | const valBackgroundImageRepeat = optBackgroundImage[0].value2; 246 | const valBackgroundImageAlign = optBackgroundImage[0].value3; 247 | const valBackgroundImageFixed = optBackgroundImage[0].value4; 248 | // 画像URL 249 | if (valBackgroundImageSrc != "") { 250 | document.body.style.backgroundImage = 251 | "url(" + valBackgroundImageSrc + ")"; 252 | } 253 | // 画像の繰り返し 254 | switch (valBackgroundImageRepeat) { 255 | case "Both": 256 | document.body.style.backgroundRepeat = "repeat"; 257 | break; 258 | case "Horizontally": 259 | document.body.style.backgroundRepeat = "repeat-x"; 260 | break; 261 | case "Vertically": 262 | document.body.style.backgroundRepeat = "repeat-y"; 263 | break; 264 | case "None": 265 | document.body.style.backgroundRepeat = "no-repeat"; 266 | break; 267 | default: 268 | document.body.style.backgroundRepeat = "no-repeat"; 269 | } 270 | // 画像の位置 271 | switch (valBackgroundImageAlign) { 272 | case "Center": 273 | document.body.style.backgroundPosition = "center top"; 274 | break; 275 | case "Left": 276 | document.body.style.backgroundPosition = "left top"; 277 | break; 278 | case "Right": 279 | document.body.style.backgroundPosition = "right top"; 280 | break; 281 | default: 282 | document.body.style.backgroundPosition = "center top"; 283 | } 284 | // 画像の固定 285 | if (valBackgroundImageFixed == "✅") { 286 | document.body.style.backgroundAttachment = "fixed"; 287 | } 288 | } catch (error) { 289 | console.error("Error: Background Image"); 290 | } 291 | 292 | // Content Background Color(Hex) 293 | try { 294 | const optContentBackground = array.filter( 295 | (value) => value.option === "Content Background Color(Hex)" 296 | ); 297 | // テーマカラー判定で使うので const ではなく var 298 | var valContentBackgroundColor = optContentBackground[0].value1; 299 | const valContentBackgroundOpacity = optContentBackground[0].value2; 300 | if (valContentBackgroundColor != "") { 301 | document.head.insertAdjacentHTML( 302 | "beforeend", 303 | "" 306 | ); 307 | const domContentBackground = document.querySelector(".js-containerMask"); 308 | domContentBackground.style.opacity = valContentBackgroundOpacity; 309 | document.body.classList.add("is-bgMask-enabled"); 310 | } 311 | } catch (error) { 312 | console.error("Error: Background mask opacity"); 313 | } 314 | 315 | // Theme 316 | try { 317 | // 文字色(白・黒)を背景色のカラーコードから判定 318 | var valThemeTextColor = blackOrWhite(valContentBackgroundColor); 319 | switch (valThemeTextColor) { 320 | case "black": 321 | document.documentElement.setAttribute("data-theme", "Light"); 322 | break; 323 | case "white": 324 | document.documentElement.setAttribute("data-theme", "Dark"); 325 | break; 326 | default: 327 | break; 328 | } 329 | } catch (error) { 330 | console.error("Error: theme"); 331 | } 332 | 333 | ///////////////////////////////////// 334 | // -Cover- 335 | 336 | try { 337 | const domCover = document.querySelector(".js-cover-img"); 338 | // 画像URL 339 | if (valCoverSrc != "") { 340 | domCover.setAttribute("src", valCoverSrc); 341 | } else { 342 | document.querySelector(".js-cover").remove(); 343 | } 344 | } catch (error) { 345 | console.error("Error: Cover"); 346 | } 347 | 348 | ///////////////////////////////////// 349 | // -Overview- 350 | 351 | // Art Image 352 | try { 353 | const optArtImage = array.filter((value) => value.option === "Art Image"); 354 | const valArtImageSrc = optArtImage[0].value1; 355 | const domArtImage = document.querySelector(".js-art-img"); 356 | // 画像URL 357 | if (valArtImageSrc != "") { 358 | domArtImage.setAttribute("src", valArtImageSrc); 359 | document.getElementById("art-empty").remove(); 360 | } else { 361 | document.getElementById("art").remove(); 362 | } 363 | } catch (error) { 364 | console.error("Error: Art Image"); 365 | } 366 | 367 | // Work Title 368 | try { 369 | const domTitle = document.querySelector(".js-title"); 370 | domTitle.textContent = valWorkTitle; 371 | } catch (error) { 372 | console.error("Error: Title"); 373 | } 374 | 375 | // Organization 376 | try { 377 | const domOrganization = document.querySelector(".js-organizationName"); 378 | domOrganization.textContent = valOrganization; 379 | } catch (error) { 380 | console.error("Error: Organization"); 381 | } 382 | 383 | // Specification 384 | try { 385 | const domSpecification = document.querySelector( 386 | ".js-specification-content" 387 | ); 388 | const optSpecification = array.filter( 389 | (value) => value.option === "Specification" 390 | ); 391 | const valSpecification = optSpecification[0].value1; 392 | domSpecification.textContent = valSpecification; 393 | } catch (error) { 394 | console.error("Error: Overview Specification"); 395 | } 396 | 397 | // Release Date 398 | try { 399 | const domReleaseDate = document.querySelector(".js-releaseDate-content"); 400 | const optReleaseDate = array.filter( 401 | (value) => value.option === "Release Date" 402 | ); 403 | const valReleaseDate = optReleaseDate[0].value1; 404 | domReleaseDate.textContent = valReleaseDate; 405 | } catch (error) { 406 | console.error("Error: Overview Release Date"); 407 | } 408 | 409 | // Location 410 | try { 411 | const domLocation = document.querySelector(".js-location-content"); 412 | const optLocation = array.filter((value) => value.option === "Location"); 413 | const valLocation = optLocation[0].value1; 414 | domLocation.textContent = valLocation; 415 | // 空欄ならHTMLから非表示 416 | if (valLocation == "") { 417 | document.querySelector(".js-overview-label").remove(); 418 | } 419 | } catch (error) { 420 | console.error("Error: Overview Location"); 421 | } 422 | 423 | // Price 424 | try { 425 | const domPrice = document.querySelector(".js-price-content"); 426 | const optPrice = array.filter((value) => value.option === "Price"); 427 | const valPrice = optPrice[0].value1; 428 | domPrice.textContent = valPrice; 429 | } catch (error) { 430 | console.error("Error: Overview Price"); 431 | } 432 | 433 | // Hashtag 434 | try { 435 | const domHashtag = document.querySelector(".js-hashtag"); 436 | const domHashtagLabel = document.querySelector(".js-hashtag-label"); 437 | const domHashtagLink = document.querySelector(".js-hashtag-link"); 438 | if (valHashtag != "") { 439 | domHashtagLink.textContent = "#" + valHashtag; 440 | const HashtagLink = 441 | "https://twitter.com/hashtag/" + valHashtag + "?src=hash"; 442 | domHashtagLink.setAttribute("href", HashtagLink); 443 | } else { 444 | domHashtag.remove(); 445 | domHashtagLabel.remove(); 446 | } 447 | } catch (error) { 448 | console.error("Error: Overview hashtag"); 449 | } 450 | 451 | ///////////////////////////////////// 452 | // -Store- 453 | // Store Heading (Option) 454 | try { 455 | const domStoreHeading = document.querySelector(".js-store-heading"); 456 | const optStoreHeading = array.filter( 457 | (value) => value.option === "Store Heading" 458 | ); 459 | const valStoreHeading = optStoreHeading[0].value1; 460 | domStoreHeading.textContent = valStoreHeading; 461 | // 空欄ならHTMLから非表示 462 | if (valStoreHeading == "") { 463 | document.querySelector(".js-section-store").remove(); 464 | } 465 | } catch (error) { 466 | console.error("Error: Store heading"); 467 | } 468 | // Store (Option) 469 | try { 470 | const domStoreWrap = document.querySelector(".js-store-wrap"); 471 | const domStore = document.querySelector(".js-store-link"); // コピー元を取得 472 | const optStore = array.filter((value) => value.option === "Store"); 473 | for (let i = 0; i < optStore.length; i++) { 474 | const domStoreClone = domStore.cloneNode(true); 475 | // option 476 | if (optStore[i].value1 != "") { 477 | domStoreClone.textContent = optStore[i].value1; 478 | domStoreClone.setAttribute("href", optStore[i].value2); 479 | } 480 | domStoreWrap.appendChild(domStoreClone); 481 | } 482 | domStore.remove(); // コピー元を削除 483 | } catch (error) { 484 | console.error("Error: Store"); 485 | } 486 | 487 | ///////////////////////////////////// 488 | // -Share Buttons- 489 | try { 490 | const domShareTwitter = document.querySelector(".js-share-tw"); 491 | const domShareFacebook = document.querySelector(".js-share-fb"); 492 | let twitterLink = 493 | "https://twitter.com/share?text=" + encodedSiteTitle + "&url=" + siteUrl; 494 | // ハッシュタグが設定されていればシェアURLに含める 495 | if (valHashtag != "") { 496 | twitterLink += "&hashtags=" + valHashtag; 497 | } 498 | domShareTwitter.setAttribute("href", twitterLink); 499 | const facebookLink = "http://www.facebook.com/sharer.php?u=" + siteUrl; 500 | domShareFacebook.setAttribute("href", facebookLink); 501 | } catch (error) { 502 | console.error("Error: Share buttons"); 503 | } 504 | 505 | ///////////////////////////////////// 506 | // -Embedded Players- 507 | 508 | // SoundCloud 509 | try { 510 | const domSoundCloudPlayer = document.getElementById("soundcloud-embed"); 511 | const valPlayerSoundCloud = array.filter( 512 | (value) => value.option === "Player (SoundCloud)" 513 | )[0].value2; 514 | const soundCloudType = array.filter( 515 | (value) => value.option === "Player (SoundCloud)" 516 | )[0].value1; 517 | if (valPlayerSoundCloud != "") { 518 | switch (soundCloudType) { 519 | case "Track": 520 | domSoundCloudPlayer.setAttribute( 521 | "src", 522 | "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/" + 523 | valPlayerSoundCloud + 524 | "&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true" 525 | ); 526 | break; 527 | case "Playlist": 528 | domSoundCloudPlayer.setAttribute( 529 | "src", 530 | "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/playlists/" + 531 | valPlayerSoundCloud + 532 | "&color=%23ff5500&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true" 533 | ); 534 | break; 535 | default: 536 | break; 537 | } 538 | } else { 539 | domSoundCloudPlayer.remove(); 540 | } 541 | } catch (error) { 542 | console.error("Error: SoundCloud Player"); 543 | } 544 | 545 | // YouTube 546 | try { 547 | const domYouTubePlayer = document.getElementById("youtube-embed"); 548 | const valPlayerYouTube = array.filter( 549 | (value) => value.option === "Player (YouTube)" 550 | )[0].value2; 551 | if (valPlayerYouTube != "") { 552 | domYouTubePlayer 553 | .querySelector(".js-embedded-player") 554 | .setAttribute( 555 | "src", 556 | "https://www.youtube.com/embed/" + valPlayerYouTube 557 | ); 558 | } else { 559 | domYouTubePlayer.remove(); 560 | } 561 | } catch (error) { 562 | console.error("Error: YouTube Player"); 563 | } 564 | 565 | ///////////////////////////////////// 566 | // -About- 567 | // About Heading 568 | try { 569 | const domAboutHeading = document.querySelector(".js-about-heading"); 570 | const optAboutHeading = array.filter( 571 | (value) => value.option === "About Heading" 572 | ); 573 | const valAboutHeading = optAboutHeading[0].value1; 574 | domAboutHeading.textContent = valAboutHeading; 575 | } catch (error) { 576 | console.error("Error: About heading"); 577 | } 578 | 579 | // About 580 | try { 581 | const domAboutWrap = document.querySelector(".js-about-wrap"); 582 | const domAbout = document.querySelector(".js-about"); // コピー元を取得 583 | for (let i = 0; i < optAbout.length; i++) { 584 | const domAboutClone = domAbout.cloneNode(true); 585 | domAboutClone.textContent = optAbout[i].value1; 586 | domAboutWrap.appendChild(domAboutClone); 587 | } 588 | domAbout.remove(); // コピー元を削除 589 | } catch (error) { 590 | console.error("Error: About"); 591 | } 592 | 593 | ///////////////////////////////////// 594 | // -Gallery- 595 | try { 596 | const optGallery = array.filter((value) => value.option === "Gallery"); 597 | const domGalleryWrap = document.querySelector(".js-dom-gallery-wrap"); 598 | const domGallery = document.querySelector(".js-dom-gallery"); // コピー元を取得 599 | 600 | // lightbox 601 | const domGalleryLightboxWrap = document.querySelector( 602 | ".js-dom-gallery-lightbox-wrap" 603 | ); 604 | const domGalleryLightbox = document.querySelector( 605 | ".js-dom-gallery-lightbox" 606 | ); // コピー元を取得 607 | 608 | for (let i = 0; i < optGallery.length; i++) { 609 | const domGalleryClone = domGallery.cloneNode(true); 610 | domGalleryClone.setAttribute("data-index", i + 1); // lightbox のために data 属性を振る 611 | domGalleryClone 612 | .querySelector(".js-dom-gallery-img") 613 | .setAttribute("src", optGallery[i].value1); 614 | domGalleryWrap.appendChild(domGalleryClone); 615 | 616 | // lightbox 617 | const domGalleryLightboxClone = domGalleryLightbox.cloneNode(true); 618 | domGalleryLightboxClone.setAttribute("data-index", i + 1); // lightbox のために data 属性を振る 619 | domGalleryLightboxClone 620 | .querySelector(".js-dom-gallery-lightbox-img") 621 | .setAttribute("src", optGallery[i].value1); 622 | domGalleryLightboxWrap.appendChild(domGalleryLightboxClone); 623 | } 624 | domGallery.remove(); // コピー元を削除 625 | domGalleryLightbox.remove(); // コピー元を削除 626 | // 空欄ならHTMLからセクションごと非表示 627 | if (optGallery[0].value1 == "") { 628 | document.getElementById("gallery").remove(); 629 | } 630 | } catch (error) { 631 | console.error("Error: Gallery"); 632 | } 633 | 634 | ///////////////////////////////////// 635 | // -Tracklist- 636 | // Tracklist Heading 637 | try { 638 | const domTracklistHeading = document.querySelector(".js-tracklist-heading"); 639 | const optTracklistHeading = array.filter( 640 | (value) => value.option === "Tracklist Heading" 641 | ); 642 | const valTracklistHeading = optTracklistHeading[0].value1; 643 | domTracklistHeading.textContent = valTracklistHeading; 644 | // 空欄ならHTMLからセクションごと非表示 645 | if (valTracklistHeading == "") { 646 | document.getElementById("tracklist").remove(); 647 | } 648 | } catch (error) { 649 | console.error("Error: Tracklist heading"); 650 | } 651 | 652 | // Tracklist 653 | try { 654 | const domTrackWrap = document.querySelector(".js-track-wrap"); 655 | const domTrack = document.querySelector(".js-track"); // コピー元を取得 656 | const optTrack = array.filter((value) => value.option === "Track"); 657 | for (let i = 0; i < optTrack.length; i++) { 658 | const domTrackClone = domTrack.cloneNode(true); 659 | // track title 660 | domTrackClone.querySelector(".js-track-name").textContent = 661 | optTrack[i].value1; 662 | // track description 663 | if (optTrack[i].value2 != "") { 664 | domTrackClone.querySelector(".js-track-description").textContent = 665 | optTrack[i].value2; 666 | } else { 667 | domTrackClone.querySelector(".js-track-description").remove(); 668 | } 669 | // track titleが空欄でなければ配置 670 | if (optTrack[i].value1 != "") { 671 | domTrackWrap.appendChild(domTrackClone); 672 | } 673 | } 674 | domTrack.remove(); // コピー元を削除 675 | } catch (error) { 676 | console.error("Error: Track"); 677 | } 678 | 679 | ///////////////////////////////////// 680 | // -Member- 681 | // Member Heading 682 | try { 683 | const domMemberHeading = document.querySelector(".js-member-heading"); 684 | const optMemberHeading = array.filter( 685 | (value) => value.option === "Member Heading" 686 | ); 687 | const valMemberHeading = optMemberHeading[0].value1; 688 | domMemberHeading.textContent = valMemberHeading; 689 | } catch (error) { 690 | console.error("Error: Member heading"); 691 | } 692 | 693 | // Member 694 | try { 695 | const domMemberWrap = document.querySelector(".js-member-wrap"); 696 | const domMember = document.querySelector(".js-member"); // コピー元を取得 697 | const optMember = array.filter((value) => value.option === "Member"); 698 | for (let i = 0; i < optMember.length; i++) { 699 | const domMemberClone = domMember.cloneNode(true); 700 | domMemberClone.querySelector(".js-member-name").textContent = 701 | optMember[i].value1; 702 | // option 703 | if (optMember[i].value2 != "") { 704 | domMemberClone.querySelector(".js-member-role").textContent = 705 | optMember[i].value2; 706 | } else { 707 | domMemberClone.querySelector(".js-member-role").remove(); 708 | } 709 | if (optMember[i].value3 != "") { 710 | domMemberClone 711 | .querySelector(".js-member-url") 712 | .setAttribute("href", optMember[i].value3); 713 | } else { 714 | domMemberClone.querySelector(".js-member-link").remove(); 715 | } 716 | domMemberWrap.appendChild(domMemberClone); 717 | } 718 | domMember.remove(); // コピー元を削除 719 | } catch (error) { 720 | console.error("Error: Member"); 721 | } 722 | 723 | ///////////////////////////////////// 724 | // -Organization- 725 | 726 | // Organization Logo 727 | try { 728 | const optOrganizationLogo = array.filter( 729 | (value) => value.option === "Organization Logo" 730 | ); 731 | const valOrganizationLogoSrc = optOrganizationLogo[0].value1; 732 | const domOrganizationLogo = document.querySelector( 733 | ".js-organization-logo-img" 734 | ); 735 | // 画像URL 736 | if (valOrganizationLogoSrc != "") { 737 | domOrganizationLogo.setAttribute("src", valOrganizationLogoSrc); 738 | domOrganizationLogo.setAttribute("alt", valOrganization); 739 | } else { 740 | domOrganizationLogo.remove(); 741 | document.querySelector(".js-organization-logo").textContent = 742 | valOrganization; 743 | } 744 | } catch (error) { 745 | console.error("Error: Organization Logo"); 746 | } 747 | 748 | // Organization Links 749 | try { 750 | const domOrganizationLinkWrap = document.querySelector( 751 | ".js-organization-link-wrap" 752 | ); 753 | const domOrganizationLink = document.querySelector(".js-organization-link"); // コピー元を取得 754 | const optOrganizationLink = array.filter( 755 | (value) => value.option === "Organization Link" 756 | ); 757 | 758 | for (let i = 0; i < optOrganizationLink.length; i++) { 759 | const domOrganizationLinkClone = domOrganizationLink.cloneNode(true); 760 | domOrganizationLinkClone.setAttribute( 761 | "href", 762 | optOrganizationLink[i].value2 763 | ); 764 | domOrganizationLinkClone.querySelector( 765 | ".js-organization-link-label" 766 | ).textContent = optOrganizationLink[i].value1; 767 | 768 | domOrganizationLinkWrap.appendChild(domOrganizationLinkClone); 769 | } 770 | domOrganizationLink.remove(); // コピー元を削除 771 | // 空欄ならHTMLから非表示 772 | if (optOrganizationLink[0].value1 == "") { 773 | domOrganizationLinkWrap.remove(); 774 | } 775 | } catch (error) { 776 | console.error("Error: Organization Links"); 777 | } 778 | 779 | ///////////////////////////////////// 780 | // -Footer- 781 | document.querySelector(".js-footer-workTitle").textContent = valWorkTitle; 782 | // footer-text (option) 783 | try { 784 | const domFooterText = document.querySelector(".js-footer-text"); 785 | const optFooterText = array.filter( 786 | (value) => value.option === "Footer Text" 787 | ); 788 | const valFooterText = optFooterText[0].value1; 789 | if (valFooterText != "") { 790 | domFooterText.textContent = valFooterText; 791 | } else { 792 | domFooterText.remove(); 793 | } 794 | } catch (error) { 795 | console.error("Error: Footer text"); 796 | } 797 | 798 | ///////////////////////////////////// 799 | // -Download- 800 | // クエリパラメータが?prebuild=trueのときテンプレートをダウンロード 801 | const urlParam = location.search; 802 | if (urlParam === "?prebuild=true") { 803 | // プレビュー用バナーを消す 804 | document.querySelector(".js-prebuild").remove(); 805 | // 検索避けない設定の場合noindex消す 806 | const valRobots = array.filter( 807 | (value) => value.option === "Hide on Search Results" 808 | )[0].value1; 809 | if (valRobots == "-") { 810 | document.getElementById("meta-robots").remove(); 811 | } 812 | // jsでの書き換えがロードしきってからDOMを取得する 813 | window.addEventListener("load", function () { 814 | let snapshot = new XMLSerializer().serializeToString(document); 815 | // 不要な要素をhtml文字列から抜き取る 816 | snapshot = snapshot.replace( 817 | '', 818 | "" 819 | ); 820 | snapshot = snapshot.replace( 821 | '', 822 | "" 823 | ); 824 | // ダウンロード 825 | let blob = new Blob([snapshot], { type: "text/plan" }); 826 | let link = document.createElement("a"); 827 | link.href = URL.createObjectURL(blob); 828 | link.download = "index.html"; 829 | link.click(); 830 | }); 831 | } 832 | } 833 | --------------------------------------------------------------------------------