├── .prettierignore ├── static ├── favicon.ico ├── img │ ├── github-blog.png │ └── logo │ │ ├── github.png │ │ └── netlify.svg └── README.md ├── .prettierrc.js ├── plugins ├── infinite-loading.js ├── prism.js ├── github-api-v3.js └── vue-notifications.js ├── .gitignore ├── assets ├── css │ ├── mixin │ │ └── _mediaquery.scss │ ├── _vars.scss │ └── base.scss └── README.md ├── .editorconfig ├── layouts ├── README.md └── default.vue ├── pages ├── README.md └── index.vue ├── .envrc.example ├── middleware └── README.md ├── store ├── README.md └── index.js ├── .eslintrc.js ├── apollo ├── client-configs │ └── default.js └── queries │ ├── getPrevIssues.gql │ └── getIssues.gql ├── components ├── AppHeader.vue ├── AppFooter.vue └── EntryItem.vue ├── LICENSE ├── package.json ├── README.md └── nuxt.config.js /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | package-lock.json 3 | yarn.lock 4 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miyaoka/gh-blog/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /static/img/github-blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miyaoka/gh-blog/HEAD/static/img/github-blog.png -------------------------------------------------------------------------------- /static/img/logo/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/miyaoka/gh-blog/HEAD/static/img/logo/github.png -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: false, 3 | singleQuote: true, 4 | arrowParens: 'always' 5 | } 6 | -------------------------------------------------------------------------------- /plugins/infinite-loading.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import InfiniteLoading from 'vue-infinite-loading' 3 | 4 | Vue.component('infinite-loading', InfiniteLoading) 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules 3 | 4 | # logs 5 | npm-debug.log 6 | 7 | # Nuxt build 8 | .nuxt 9 | 10 | # Nuxt generate 11 | dist 12 | 13 | .envrc 14 | -------------------------------------------------------------------------------- /plugins/prism.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Prism from 'prismjs' 3 | 4 | Vue.use(Prism) 5 | 6 | Vue.mixin({ 7 | mounted() { 8 | Prism.highlightAll() 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /assets/css/mixin/_mediaquery.scss: -------------------------------------------------------------------------------- 1 | $breakpoints: ('sp': 'screen and (max-width: 600px)', 'tb': 'screen and (max-width: 800px)') 2 | !default; 3 | 4 | @mixin mq($breakpoint: sp) { 5 | @media #{map-get($breakpoints, $breakpoint)} { 6 | @content; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /layouts/README.md: -------------------------------------------------------------------------------- 1 | # LAYOUTS 2 | 3 | This directory contains your Application Layouts. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/views#layouts 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /pages/README.md: -------------------------------------------------------------------------------- 1 | # PAGES 2 | 3 | This directory contains your Application Views and Routes. 4 | The framework reads all the .vue files inside this directory and creates the router of your application. 5 | 6 | More information about the usage of this directory in the documentation: 7 | https://nuxtjs.org/guide/routing 8 | -------------------------------------------------------------------------------- /plugins/github-api-v3.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | export default ({ env }, inject) => { 4 | inject( 5 | 'ghApiV3', 6 | axios.create({ 7 | baseURL: 'https://api.github.com', 8 | timeout: 10000, 9 | headers: { authorization: `token ${env.GH_WRITE_TOKEN}` } 10 | }) 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /assets/README.md: -------------------------------------------------------------------------------- 1 | # ASSETS 2 | 3 | This directory contains your un-compiled assets such as LESS, SASS, or JavaScript. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/assets#webpacked 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /.envrc.example: -------------------------------------------------------------------------------- 1 | # Create your tokens at https://github.com/settings/tokens 2 | 3 | ## Public token to fetch repository on production 4 | export GH_READONLY_TOKEN= 5 | 6 | ## Private token to edit repository on local. Don't use in public!!! 7 | export GH_WRITE_TOKEN= 8 | 9 | ## Target repository 10 | export GH_REPO_OWNER= 11 | export GH_REPO_NAME= 12 | -------------------------------------------------------------------------------- /static/README.md: -------------------------------------------------------------------------------- 1 | # STATIC 2 | 3 | This directory contains your static files. 4 | Each file inside this directory is mapped to /. 5 | 6 | Example: /static/robots.txt is mapped as /robots.txt. 7 | 8 | More information about the usage of this directory in the documentation: 9 | https://nuxtjs.org/guide/assets#static 10 | 11 | **This directory is not required, you can delete it if you don't want to use it.** 12 | -------------------------------------------------------------------------------- /middleware/README.md: -------------------------------------------------------------------------------- 1 | # MIDDLEWARE 2 | 3 | This directory contains your Application Middleware. 4 | The middleware lets you define custom function to be ran before rendering a page or a group of pages (layouts). 5 | 6 | More information about the usage of this directory in the documentation: 7 | https://nuxtjs.org/guide/routing#middleware 8 | 9 | **This directory is not required, you can delete it if you don't want to use it.** 10 | -------------------------------------------------------------------------------- /store/README.md: -------------------------------------------------------------------------------- 1 | # STORE 2 | 3 | This directory contains your Vuex Store files. 4 | Vuex Store option is implemented in the Nuxt.js framework. 5 | Creating a index.js file in this directory activate the option in the framework automatically. 6 | 7 | More information about the usage of this directory in the documentation: 8 | https://nuxtjs.org/guide/vuex-store 9 | 10 | **This directory is not required, you can delete it if you don't want to use it.** 11 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true 6 | }, 7 | parserOptions: { 8 | parser: 'babel-eslint' 9 | }, 10 | extends: [ 11 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention 12 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 13 | 'plugin:vue/essential' 14 | ], 15 | // required to lint *.vue files 16 | plugins: [ 17 | 'vue' 18 | ], 19 | // add your custom rules here 20 | rules: {} 21 | } 22 | -------------------------------------------------------------------------------- /assets/css/_vars.scss: -------------------------------------------------------------------------------- 1 | $clr-1: hsl(14, 89%, 66%); 2 | $clr-1-l: hsl(14, 89%, 76%); 3 | $clr-1-d: hsl(14, 89%, 56%); 4 | 5 | $clr-2: hsl(186, 51%, 81%); 6 | $clr-2-l: hsl(186, 51%, 91%); 7 | $clr-2-d: hsl(186, 51%, 71%); 8 | 9 | $clr-w: hsl(0, 0%, 95%); 10 | $clr-w-l: hsl(0, 0%, 97%); 11 | $clr-w-ll: hsl(0, 0%, 100%); 12 | $clr-w-d: hsl(0, 0%, 90%); 13 | $clr-w-dd: hsl(0, 0%, 80%); 14 | 15 | $clr-b: hsl(0, 0%, 30%); 16 | $clr-b-l: hsl(0, 0%, 45%); 17 | $clr-b-ll: hsl(0, 0%, 60%); 18 | $clr-b-d: hsl(0, 0%, 15%); 19 | $clr-b-dd: hsl(0, 0%, 0%); 20 | 21 | $clr-smrn: hsl(209, 30%, 50%); 22 | $clr-smrn-l: hsl(209, 30%, 60%); 23 | $clr-smrn-d: hsl(209, 30%, 40%); 24 | -------------------------------------------------------------------------------- /apollo/client-configs/default.js: -------------------------------------------------------------------------------- 1 | import { ApolloLink } from 'apollo-link' 2 | import { HttpLink } from 'apollo-link-http' 3 | import { InMemoryCache } from 'apollo-cache-inmemory' 4 | 5 | export default (ctx) => { 6 | const httpLink = new HttpLink({ uri: 'https://api.github.com/graphql' }) 7 | 8 | // middleware 9 | const middlewareLink = new ApolloLink((operation, forward) => { 10 | const token = ctx.env.GH_READONLY_TOKEN 11 | 12 | operation.setContext({ 13 | headers: { authorization: `Bearer ${token}` } 14 | }) 15 | return forward(operation) 16 | }) 17 | const link = middlewareLink.concat(httpLink) 18 | return { 19 | link, 20 | cache: new InMemoryCache() 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /components/AppHeader.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 12 | 13 | 39 | -------------------------------------------------------------------------------- /apollo/queries/getPrevIssues.gql: -------------------------------------------------------------------------------- 1 | query getPrevIssues( 2 | $repoOwner: String! 3 | $repoName: String! 4 | $fetchIssueCount: Int = 5 5 | $startCursor: String 6 | ) { 7 | repository(owner: $repoOwner, name: $repoName) { 8 | name 9 | description 10 | issues( 11 | orderBy: { field: CREATED_AT, direction: DESC } 12 | last: $fetchIssueCount 13 | before: $startCursor 14 | ) { 15 | totalCount 16 | pageInfo { 17 | startCursor 18 | endCursor 19 | hasPreviousPage 20 | hasNextPage 21 | } 22 | nodes { 23 | author { 24 | avatarUrl 25 | login 26 | resourcePath 27 | url 28 | } 29 | id 30 | number 31 | title 32 | body 33 | createdAt 34 | updatedAt 35 | url 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Masaya Kazama 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /plugins/vue-notifications.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueNotifications from 'vue-notifications' 3 | import Noty from 'noty' // https://github.com/needim/noty 4 | import 'noty/lib/noty.css' 5 | import 'noty/lib/themes/sunset.css' 6 | function toast({ title, message, type, timeout, cb }) { 7 | if (type === VueNotifications.types.warn) type = 'warning' 8 | return new Noty({ theme: 'sunset', text: message, timeout, type }).show() 9 | } 10 | 11 | const options = { 12 | success: toast, 13 | error: toast, 14 | info: toast, 15 | warn: toast 16 | } 17 | 18 | Vue.use(VueNotifications, options) 19 | 20 | Vue.mixin({ 21 | notifications: { 22 | showSuccessMsg: { 23 | type: VueNotifications.types.success, 24 | title: 'Success', 25 | timeout: 1000 26 | }, 27 | showInfoMsg: { 28 | type: VueNotifications.types.info, 29 | title: 'Info' 30 | }, 31 | showWarnMsg: { 32 | type: VueNotifications.types.warn, 33 | title: 'Warning' 34 | }, 35 | showErrorMsg: { 36 | type: VueNotifications.types.error, 37 | title: 'Error', 38 | timeout: 7000 39 | } 40 | } 41 | }) 42 | -------------------------------------------------------------------------------- /apollo/queries/getIssues.gql: -------------------------------------------------------------------------------- 1 | query getIssues( 2 | $repoOwner: String! 3 | $repoName: String! 4 | $fetchCommentsPerIssue: Int = 5 5 | $fetchIssuePerPage: Int = 5 6 | $endCursor: String 7 | ) { 8 | repository(owner: $repoOwner, name: $repoName) { 9 | name 10 | description 11 | issues( 12 | orderBy: { field: CREATED_AT, direction: DESC } 13 | first: $fetchIssuePerPage 14 | after: $endCursor 15 | ) { 16 | totalCount 17 | pageInfo { 18 | startCursor 19 | endCursor 20 | hasPreviousPage 21 | hasNextPage 22 | } 23 | nodes { 24 | author { 25 | avatarUrl 26 | login 27 | resourcePath 28 | url 29 | } 30 | id 31 | number 32 | title 33 | body 34 | createdAt 35 | updatedAt 36 | url 37 | comments(last: $fetchCommentsPerIssue) { 38 | totalCount 39 | nodes { 40 | author { 41 | avatarUrl 42 | login 43 | resourcePath 44 | url 45 | } 46 | id 47 | url 48 | } 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gh-blog", 3 | "version": "1.0.0", 4 | "description": "GH Blog", 5 | "author": "Masaya Kazama ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "nuxt", 9 | "build": "nuxt build", 10 | "start": "nuxt start", 11 | "generate": "nuxt generate", 12 | "lint": "eslint --ext .js,.vue --ignore-path .gitignore .", 13 | "precommit": "npm run lint" 14 | }, 15 | "dependencies": { 16 | "@nuxtjs/apollo": "^3.0.4", 17 | "@nuxtjs/axios": "^5.1.1", 18 | "@nuxtjs/google-analytics": "^2.0.2", 19 | "apollo-link-http": "^1.5.2", 20 | "graphql-tag": "^2.8.0", 21 | "luxon": "^0.5.3", 22 | "modern-normalize": "^0.4.0", 23 | "noty": "^3.2.0-beta", 24 | "nuxt": "^1.4.0", 25 | "prismjs": "^1.12.0", 26 | "vue-infinite-loading": "^2.2.3", 27 | "vue-markdown": "^2.2.4", 28 | "vue-notifications": "^0.9.0" 29 | }, 30 | "devDependencies": { 31 | "ajv": "^6.2.0", 32 | "babel-eslint": "^8.2.2", 33 | "eslint": "^4.18.2", 34 | "eslint-friendly-formatter": "^3.0.0", 35 | "eslint-loader": "^2.0.0", 36 | "eslint-plugin-vue": "^4.3.0", 37 | "graphql": "^0.11.7", 38 | "node-sass": "^4.7.2", 39 | "sass-loader": "^6.0.7" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /components/AppFooter.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 29 | 30 | 55 | -------------------------------------------------------------------------------- /layouts/default.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 35 | 36 | 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![github-blog](https://user-images.githubusercontent.com/1443118/37141522-a05a276a-22f8-11e8-9d4c-652150986e93.png) 2 | 3 | # gh-blog 4 | 5 | > GitHub Issue as Blog 6 | 7 | ## Article 8 | 9 | - [tweet: "azuさんがGitHubのIssueをコンテンツに使う話してて面白そうだったので、とりあえず作ってみてる"](https://twitter.com/miyaoka/status/970040889513922561) 10 | - [GitHub Issuesでブログを作る - Qiita](https://qiita.com/miyaoka/items/1922d5d8528fe31016b9) 11 | 12 | ## Demo 13 | 14 | Demo site: https://gh-blog.netlify.com/ 15 | 16 | 17 | 18 | ## Env settings 19 | 20 | ### Use direnv 21 | 22 | * Copy `.envrc.example` to `.envrc` 23 | 24 | ### Fill out params 25 | 26 | Create your OAuth tokens at [Personal Access Tokens](https://github.com/settings/tokens), and set below. 27 | 28 | * `GH_READONLY_TOKEN`: (Required) To fetch issues. 29 | * Select scopes: Turn off all scopes. (will display as `public access`) 30 | * `GH_WRITE_TOKEN`: (Optional) To edit issues on blog site. Don't use in public!! 31 | * Select scopes: Only `public_repo` scope. 32 | 33 | Set target repository 34 | 35 | * `GH_REPO_OWNER` 36 | * `GH_REPO_NAME` 37 | 38 | ## Build Setup 39 | 40 | ```bash 41 | # install dependencies 42 | $ npm install # Or yarn install 43 | 44 | # serve with hot reload at localhost:3000 45 | $ npm run dev 46 | 47 | # build for production and launch server 48 | $ npm run build 49 | $ npm start 50 | 51 | # generate static project 52 | $ npm run generate 53 | ``` 54 | 55 | For detailed explanation on how things work, checkout the [Nuxt.js docs](https://github.com/nuxt/nuxt.js). 56 | -------------------------------------------------------------------------------- /store/index.js: -------------------------------------------------------------------------------- 1 | import getIssues from '~/apollo/queries/getIssues' 2 | 3 | export const state = () => ({ 4 | repoOwner: '', 5 | repoName: '', 6 | fetchIssuePerPage: 20, 7 | totalCount: 0, 8 | nodes: [], 9 | pageInfo: {} 10 | }) 11 | 12 | export const mutations = { 13 | setRepoOwner(state, repoOwner) { 14 | state.repoOwner = repoOwner 15 | }, 16 | setRepoName(state, repoName) { 17 | state.repoName = repoName 18 | }, 19 | clearIssues(state) { 20 | state.totalCount = 0 21 | state.nodes = [] 22 | state.pageInfo = {} 23 | }, 24 | setIssues(state, { totalCount, nodes, pageInfo, append }) { 25 | state.totalCount = totalCount 26 | state.nodes = append ? [...state.nodes, ...nodes] : nodes 27 | state.pageInfo = pageInfo 28 | }, 29 | updateNode(state, node) { 30 | const i = state.nodes.findIndex((n) => n.id === node.id) 31 | if (i >= 0) { 32 | state.nodes = [ 33 | ...state.nodes.slice(0, i), 34 | node, 35 | ...state.nodes.slice(i + 1) 36 | ] 37 | } 38 | } 39 | } 40 | 41 | export const actions = { 42 | async nuxtServerInit({ commit, state }, { app, env }) { 43 | const { GH_REPO_OWNER: repoOwner, GH_REPO_NAME: repoName } = env 44 | 45 | commit('setRepoOwner', repoOwner) 46 | commit('setRepoName', repoName) 47 | 48 | try { 49 | const { data } = await app.apolloProvider.defaultClient.query({ 50 | query: getIssues, 51 | variables: { 52 | repoOwner, 53 | repoName, 54 | fetchIssuePerPage: state.fetchIssuePerPage 55 | } 56 | }) 57 | commit('setIssues', data.repository.issues) 58 | } catch (err) { 59 | console.error(err) 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /nuxt.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | modules: [ 3 | '@nuxtjs/apollo', 4 | ['@nuxtjs/google-analytics', { id: 'UA-3536169-21' }] 5 | ], 6 | plugins: [ 7 | '~/plugins/github-api-v3.js', 8 | { src: '~/plugins/vue-notifications', ssr: false }, 9 | '~/plugins/infinite-loading.js', 10 | '~/plugins/prism.js' 11 | ], 12 | apollo: { 13 | clientConfigs: { 14 | default: '~/apollo/client-configs/default.js' 15 | } 16 | }, 17 | css: ['~/assets/css/base.scss'], 18 | env: { 19 | GH_READONLY_TOKEN: process.env.GH_READONLY_TOKEN, 20 | GH_WRITE_TOKEN: process.env.GH_WRITE_TOKEN, 21 | GH_REPO_OWNER: process.env.GH_REPO_OWNER, 22 | GH_REPO_NAME: process.env.GH_REPO_NAME 23 | }, 24 | /* 25 | ** Headers of the page 26 | */ 27 | head: { 28 | title: 'GitHub Issue as blog', 29 | meta: [ 30 | { charset: 'utf-8' }, 31 | { name: 'viewport', content: 'width=device-width, initial-scale=1' }, 32 | { 33 | hid: 'description', 34 | name: 'description', 35 | content: 'GitHub Issue as blog' 36 | } 37 | ], 38 | link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }] 39 | }, 40 | /* 41 | ** Customize the progress bar color 42 | */ 43 | loading: { color: '#3B8070' }, 44 | /* 45 | ** Build configuration 46 | */ 47 | build: { 48 | vendor: ['vue-notifications', 'luxon'], 49 | /* 50 | ** Run ESLint on save 51 | */ 52 | extend(config, { isDev, isClient }) { 53 | if (isDev && isClient) { 54 | config.module.rules.push({ 55 | enforce: 'pre', 56 | test: /\.(js|vue)$/, 57 | loader: 'eslint-loader', 58 | exclude: /(node_modules)/ 59 | }) 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /assets/css/base.scss: -------------------------------------------------------------------------------- 1 | @import 'node_modules/modern-normalize/modern-normalize.css'; 2 | @import 'node_modules/prismjs/themes/prism.css'; 3 | @import '~assets/css/_vars.scss'; 4 | 5 | @font-face { 6 | font-family: 'Yu Gothic'; 7 | src: local('Yu Gothic Medium'); 8 | font-weight: 100; 9 | } 10 | @font-face { 11 | font-family: 'Yu Gothic'; 12 | src: local('Yu Gothic Medium'); 13 | font-weight: 200; 14 | } 15 | @font-face { 16 | font-family: 'Yu Gothic'; 17 | src: local('Yu Gothic Medium'); 18 | font-weight: 300; 19 | } 20 | @font-face { 21 | font-family: 'Yu Gothic'; 22 | src: local('Yu Gothic Medium'); 23 | font-weight: 400; 24 | } 25 | @font-face { 26 | font-family: 'Yu Gothic'; 27 | src: local('Yu Gothic Bold'); 28 | font-weight: bold; 29 | } 30 | @font-face { 31 | font-family: 'Helvetica Neue'; 32 | src: local('Helvetica Neue Regular'); 33 | font-weight: 100; 34 | } 35 | @font-face { 36 | font-family: 'Helvetica Neue'; 37 | src: local('Helvetica Neue Regular'); 38 | font-weight: 200; 39 | } 40 | 41 | body { 42 | font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', YuGothic, 43 | '游ゴシック Medium', YuGothicM, Verdana, Meiryo, sans-serif; 44 | } 45 | @media all and (-ms-high-contrast: none) { 46 | body { 47 | font-family: Verdana, Meiryo, sans-serif; 48 | } 49 | } 50 | @media all and (-ms-high-contrast: active) { 51 | body { 52 | font-family: Verdana, Meiryo, sans-serif; 53 | } 54 | } 55 | 56 | body { 57 | font-size: 16px; 58 | background: $clr-1; 59 | color: $clr-b; 60 | } 61 | 62 | h1 { 63 | font-size: 1.6rem; 64 | } 65 | h2 { 66 | font-size: 1.4rem; 67 | } 68 | h3 { 69 | font-size: 1.2rem; 70 | } 71 | h4 { 72 | font-size: 1rem; 73 | } 74 | h5 { 75 | font-size: 1rem; 76 | } 77 | h6 { 78 | font-size: 1rem; 79 | } 80 | h1, 81 | h2, 82 | h3, 83 | h4, 84 | h5, 85 | h6 { 86 | margin: 0.5rem 0; 87 | font-weight: 700; 88 | color: $clr-b-d; 89 | text-shadow: 2px 2px 1px #fff, -2px 2px 1px #fff, 2px -2px 1px #fff, 90 | -2px -2px 1px #fff; 91 | } 92 | 93 | a { 94 | text-decoration: none; 95 | } 96 | .body a { 97 | color: $clr-1; 98 | text-shadow: 2px 2px 1px #fff, -2px 2px 1px #fff, 2px -2px 1px #fff, 99 | -2px -2px 1px #fff; 100 | word-break: break-all; 101 | } 102 | 103 | blockquote { 104 | padding: 0.5rem 1rem; 105 | margin: 1rem 0; 106 | border-left: 4px solid $clr-w; 107 | font-size: 0.9rem; 108 | color: $clr-b-l; 109 | 110 | & > :first-child { 111 | margin-top: 0; 112 | } 113 | & > :last-child { 114 | margin-bottom: 0; 115 | } 116 | } 117 | 118 | iframe { 119 | max-width: 100%; 120 | } 121 | 122 | .twitter-tweet-rendered { 123 | display: inline-block !important; 124 | } 125 | 126 | .marked { 127 | word-break: break-word; 128 | 129 | img { 130 | max-width: 100%; 131 | margin: 1rem 0; 132 | } 133 | } 134 | pre { 135 | padding: 1rem; 136 | overflow: auto; 137 | background: #f5f2f0; 138 | border-radius: 0.3rem; 139 | } 140 | code { 141 | border-radius: 0.3rem; 142 | padding: 0.3rem; 143 | margin: 0.3rem; 144 | overflow-x: scroll; 145 | background: #f5f2f0; 146 | color: black; 147 | } 148 | -------------------------------------------------------------------------------- /pages/index.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 100 | 101 | 116 | 124 | -------------------------------------------------------------------------------- /components/EntryItem.vue: -------------------------------------------------------------------------------- 1 |