Refactor source paths
This commit is contained in:
197
source/app/web/statics/app.js
Normal file
197
source/app/web/statics/app.js
Normal file
@@ -0,0 +1,197 @@
|
||||
;(async function() {
|
||||
//Init
|
||||
const url = new URLSearchParams(window.location.search)
|
||||
const {data:templates} = await axios.get("/.templates")
|
||||
const {data:plugins} = await axios.get("/.plugins")
|
||||
const {data:base} = await axios.get("/.plugins.base")
|
||||
const {data:version} = await axios.get("/.version")
|
||||
//App
|
||||
return new Vue({
|
||||
//Initialization
|
||||
el:"main",
|
||||
async mounted() {
|
||||
//Load instance
|
||||
await this.load()
|
||||
//Interpolate config from browser
|
||||
try {
|
||||
this.config.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
} catch (error) {}
|
||||
},
|
||||
components:{Prism:PrismComponent},
|
||||
//Data initialization
|
||||
data:{
|
||||
version,
|
||||
user:url.get("user") || "",
|
||||
palette:url.get("palette") || (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light") || "light",
|
||||
requests:{limit:0, used:0, remaining:0, reset:0},
|
||||
config:{
|
||||
timezone:"",
|
||||
},
|
||||
plugins:{
|
||||
base,
|
||||
list:plugins,
|
||||
enabled:{base:Object.fromEntries(base.map(key => [key, true]))},
|
||||
descriptions:{
|
||||
pagespeed:"Website performances",
|
||||
languages:"Most used languages",
|
||||
followup:"Issues and pull requests",
|
||||
traffic:"Pages views",
|
||||
lines:"Lines of code changed",
|
||||
habits:"Coding habits",
|
||||
music:"Music plugin",
|
||||
posts:"Recent posts",
|
||||
isocalendar:"Isometric commit calendar",
|
||||
gists:"Gists metrics",
|
||||
topics:"Starred topics",
|
||||
projects:"Projects",
|
||||
tweets:"Latest tweets",
|
||||
"base.header":"Header",
|
||||
"base.activity":"Account activity",
|
||||
"base.community":"Community stats",
|
||||
"base.repositories":"Repositories metrics",
|
||||
"base.metadata":"Metadata",
|
||||
},
|
||||
options:{
|
||||
"languages.ignored":"",
|
||||
"languages.skipped":"",
|
||||
"pagespeed.detailed":false,
|
||||
"pagespeed.screenshot":false,
|
||||
"habits.from":200,
|
||||
"habits.days":14,
|
||||
"habits.facts":true,
|
||||
"habits.charts":false,
|
||||
"music.playlist":"",
|
||||
"music.limit":4,
|
||||
"posts.limit":4,
|
||||
"posts.source":"dev.to",
|
||||
"isocalendar.duration":"half-year",
|
||||
"projects.limit":4,
|
||||
"projects.repositories":"",
|
||||
"topics.mode":"starred",
|
||||
"topics.sort":"stars",
|
||||
"topics.limit":12,
|
||||
"tweets.limit":2,
|
||||
},
|
||||
},
|
||||
templates:{
|
||||
list:templates,
|
||||
selected:url.get("template") || templates[0],
|
||||
loaded:{},
|
||||
placeholder:"",
|
||||
descriptions:{
|
||||
classic:"Classic template",
|
||||
terminal:"Terminal template",
|
||||
repository:"(hidden)",
|
||||
},
|
||||
},
|
||||
generated:{
|
||||
pending:false,
|
||||
content:"",
|
||||
error:false,
|
||||
},
|
||||
},
|
||||
//Computed data
|
||||
computed:{
|
||||
//User's repository
|
||||
repo() {
|
||||
return `https://github.com/${this.user}/${this.user}`
|
||||
},
|
||||
//Endpoint to use for computed metrics
|
||||
url() {
|
||||
//Plugins enabled
|
||||
const plugins = Object.entries(this.plugins.enabled)
|
||||
.flatMap(([key, value]) => key === "base" ? Object.entries(value).map(([key, value]) => [`base.${key}`, value]) : [[key, value]])
|
||||
.filter(([key, value]) => /^base[.]\w+$/.test(key) ? !value : value)
|
||||
.map(([key, value]) => `${key}=${+value}`)
|
||||
//Plugins options
|
||||
const options = Object.entries(this.plugins.options)
|
||||
.filter(([key, value]) => `${value}`.length)
|
||||
.filter(([key, value]) => this.plugins.enabled[key.split(".")[0]])
|
||||
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
|
||||
//Config
|
||||
const config = Object.entries(this.config).filter(([key, value]) => value).map(([key, value]) => `config.${key}=${encodeURIComponent(value)}`)
|
||||
//Template
|
||||
const template = (this.templates.selected !== templates[0]) ? [`template=${this.templates.selected}`] : []
|
||||
//Generated url
|
||||
const params = [...template, ...plugins, ...options, ...config].join("&")
|
||||
return `${window.location.protocol}//${window.location.host}/${this.user}${params.length ? `?${params}` : ""}`
|
||||
},
|
||||
//Embedded generated code
|
||||
embed() {
|
||||
return ``
|
||||
},
|
||||
//GitHub action auto-generated code
|
||||
action() {
|
||||
return [
|
||||
`# Visit https://github.com/lowlighter/metrics/blob/master/action.yml for full reference`,
|
||||
`name: GitHub metrics`,
|
||||
`on:`,
|
||||
` # Schedule updates`,
|
||||
` schedule: [{cron: "0 * * * *"}]`,
|
||||
` push: {branches: "master"}`,
|
||||
`jobs:`,
|
||||
` github-metrics:`,
|
||||
` runs-on: ubuntu-latest`,
|
||||
` steps:`,
|
||||
` - uses: lowlighter/metrics@latest`,
|
||||
` with:`,
|
||||
` # You'll need to setup a personal token in your secrets.`,
|
||||
` token: ${"$"}{{ secrets.METRICS_TOKEN }}`,
|
||||
` # GITHUB_TOKEN is a special auto-generated token used for commits`,
|
||||
` committer_token: ${"$"}{{ secrets.GITHUB_TOKEN }}`,
|
||||
``,
|
||||
` # Options`,
|
||||
` user: ${this.user }`,
|
||||
` template: ${this.templates.selected}`,
|
||||
` base: ${Object.entries(this.plugins.enabled.base).filter(([key, value]) => value).map(([key]) => key).join(", ")||'""'}`,
|
||||
...[
|
||||
...Object.entries(this.plugins.enabled).filter(([key, value]) => (key !== "base")&&(value)).map(([key]) => ` plugin_${key}: yes`),
|
||||
...Object.entries(this.plugins.options).filter(([key, value]) => value).filter(([key, value]) => this.plugins.enabled[key.split(".")[0]]).map(([key, value]) => ` plugin_${key.replace(/[.]/, "_")}: ${typeof value === "boolean" ? {true:"yes", false:"no"}[value] : value}`),
|
||||
...Object.entries(this.config).filter(([key, value]) => value).map(([key, value]) => ` config_${key.replace(/[.]/, "_")}: ${typeof value === "boolean" ? {true:"yes", false:"no"}[value] : value}`),
|
||||
].sort(),
|
||||
].join("\n")
|
||||
}
|
||||
},
|
||||
//Methods
|
||||
methods:{
|
||||
//Load and render image
|
||||
async load() {
|
||||
//Render placeholder
|
||||
const url = this.url.replace(new RegExp(`${this.user}(\\?|$)`), "placeholder$1")
|
||||
this.templates.placeholder = this.serialize((await axios.get(url)).data)
|
||||
this.generated.content = ""
|
||||
//Start GitHub rate limiter tracker
|
||||
this.ghlimit()
|
||||
},
|
||||
//Generate metrics and flush cache
|
||||
async generate() {
|
||||
//Avoid requests spamming
|
||||
if (this.generated.pending)
|
||||
return
|
||||
this.generated.pending = true
|
||||
//Compute metrics
|
||||
try {
|
||||
await axios.get(`/.uncache?&token=${(await axios.get(`/.uncache?user=${this.user}`)).data.token}`)
|
||||
this.generated.content = this.serialize((await axios.get(this.url)).data)
|
||||
} catch {
|
||||
this.generated.error = true
|
||||
}
|
||||
finally {
|
||||
this.generated.pending = false
|
||||
}
|
||||
this.ghlimit({once:true})
|
||||
},
|
||||
//Serialize svg
|
||||
serialize(svg) {
|
||||
return `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(svg)))}`
|
||||
},
|
||||
//Update reate limit requests
|
||||
async ghlimit({once = false} = {}) {
|
||||
const {data:requests} = await axios.get("/.requests")
|
||||
this.requests = requests
|
||||
if (!once)
|
||||
setTimeout(() => this.ghlimit(), 30*1000)
|
||||
}
|
||||
},
|
||||
})
|
||||
})()
|
||||
246
source/app/web/statics/index.html
Normal file
246
source/app/web/statics/index.html
Normal file
@@ -0,0 +1,246 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>📊 GitHub metrics</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="A SVG image generator which includes activity, community and repositories metrics about your GitHub account that you can includes on your profile">
|
||||
<meta name="author" content="lowlighter">
|
||||
<link rel="icon" href="data:,">
|
||||
<link rel="stylesheet" href="/.css/style.css">
|
||||
<link rel="stylesheet" href="/.css/style.prism.css" />
|
||||
</head>
|
||||
<body>
|
||||
<!-- Vue app -->
|
||||
<main :class="[palette]">
|
||||
<!-- Title -->
|
||||
<template>
|
||||
<h1><a href="https://github.com/lowlighter/metrics">Metrics v{{ version }}</a></h1>
|
||||
</template>
|
||||
<!-- Content -->
|
||||
<template>
|
||||
<section class="generator">
|
||||
<!-- Steps panel -->
|
||||
<section class="steps">
|
||||
<div class="step">
|
||||
<h2>1. Enter your GitHub username</h2>
|
||||
<input type="text" name="user" v-model="user" maxlength="39" placeholder="GitHub username" :disabled="generated.pending">
|
||||
</div>
|
||||
<div class="step">
|
||||
<h2>2. Select a template</h2>
|
||||
<div class="templates">
|
||||
<label v-for="template in templates.list" :key="template" v-show="templates.descriptions[template] !== '(hidden)'">
|
||||
<input type="radio" v-model="templates.selected" :value="template" @change="load" :disabled="generated.pending">
|
||||
{{ templates.descriptions[template] || template }}
|
||||
</label>
|
||||
</div>
|
||||
<template v-if="plugins.base.length">
|
||||
<h3>2.1 Configure base content</h3>
|
||||
<div class="plugins">
|
||||
<label v-for="part in plugins.base" :key="part">
|
||||
<input type="checkbox" v-model="plugins.enabled.base[part]" @change="load" :disabled="generated.pending">
|
||||
{{ plugins.descriptions[`base.${part}`] || `base.${part}` }}
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="plugins.list.length">
|
||||
<h3>2.2 Enable additional plugins</h3>
|
||||
<div class="plugins">
|
||||
<label v-for="plugin in plugins.list" :key="plugin">
|
||||
<input type="checkbox" v-model="plugins.enabled[plugin]" @change="load" :disabled="generated.pending">
|
||||
{{ plugins.descriptions[plugin] || plugin }}
|
||||
</label>
|
||||
</div>
|
||||
<i>*Additional plugins may be available when used as GitHub Action</i>
|
||||
<template v-if="(plugins.enabled.tweets)||(plugins.enabled.music)||(plugins.enabled.pagespeed)||(plugins.enabled.languages)||(plugins.enabled.habits)||(plugins.enabled.posts)||(plugins.enabled.isocalendar)||(plugins.enabled.projects)||(plugins.enabled.topics)">
|
||||
<h3>2.3 Configure additional plugins</h3>
|
||||
<div class="options">
|
||||
<div class="options-group" v-if="plugins.enabled.tweets">
|
||||
<h4>{{ plugins.descriptions.tweets }}</h4>
|
||||
<label>
|
||||
Number of tweets to display
|
||||
<input type="number" v-model="plugins.options['tweets.limit']" min="1" max="10" @change="load">
|
||||
</label>
|
||||
</div>
|
||||
<div class="options-group" v-if="plugins.enabled.music">
|
||||
<h4>{{ plugins.descriptions.music }}</h4>
|
||||
<label>
|
||||
Playlist embed link
|
||||
<input type="text" v-model="plugins.options['music.playlist']" placeholder="https://embed.music.apple.com/en/playlist/">
|
||||
</label>
|
||||
<label>
|
||||
Number of tracks to display
|
||||
<input type="number" v-model="plugins.options['music.limit']" min="1" @change="load">
|
||||
</label>
|
||||
</div>
|
||||
<div class="options-group" v-if="plugins.enabled.pagespeed">
|
||||
<h4>{{ plugins.descriptions.pagespeed }}</h4>
|
||||
<label>
|
||||
Detailed PageSpeed report
|
||||
<input type="checkbox" v-model="plugins.options['pagespeed.detailed']" @change="load">
|
||||
</label>
|
||||
<label>
|
||||
Include a website screenshot
|
||||
<input type="checkbox" v-model="plugins.options['pagespeed.screenshot']" @change="load">
|
||||
</label>
|
||||
</div>
|
||||
<div class="options-group" v-if="plugins.enabled.languages">
|
||||
<h4>{{ plugins.descriptions.languages }}</h4>
|
||||
<label>
|
||||
Ignored languages (comma separated)
|
||||
<input type="text" v-model="plugins.options['languages.ignored']" @change="load">
|
||||
</label>
|
||||
<label>
|
||||
Skipped repositories (comma separated)
|
||||
<input type="text" v-model="plugins.options['languages.skipped']" @change="load">
|
||||
</label>
|
||||
</div>
|
||||
<div class="options-group" v-if="plugins.enabled.habits">
|
||||
<h4>{{ plugins.descriptions.habits }}</h4>
|
||||
<label>
|
||||
Number of events for habits
|
||||
<input type="number" v-model="plugins.options['habits.from']" min="1" max="1000">
|
||||
</label>
|
||||
<label>
|
||||
Number of days for habits
|
||||
<input type="number" v-model="plugins.options['habits.days']" min="1" max="30">
|
||||
</label>
|
||||
<label>
|
||||
Display tidbits
|
||||
<input type="checkbox" v-model="plugins.options['habits.facts']" @change="load">
|
||||
</label>
|
||||
<label>
|
||||
Display activity charts
|
||||
<input type="checkbox" v-model="plugins.options['habits.charts']" @change="load">
|
||||
</label>
|
||||
</div>
|
||||
<div class="options-group" v-if="plugins.enabled.posts">
|
||||
<h4>{{ plugins.descriptions.posts }}</h4>
|
||||
<label>
|
||||
Posts source
|
||||
<select v-model="plugins.options['posts.source']" disabled>
|
||||
<option value="dev.to">dev.to</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Number of posts to display
|
||||
<input type="number" v-model="plugins.options['posts.limit']" min="1" @change="load">
|
||||
</label>
|
||||
</div>
|
||||
<div class="options-group" v-if="plugins.enabled.isocalendar">
|
||||
<h4>{{ plugins.descriptions.isocalendar }}</h4>
|
||||
<label>
|
||||
Isocalendar duration
|
||||
<select v-model="plugins.options['isocalendar.duration']">
|
||||
<option value="half-year">Half year</option>
|
||||
<option value="full-year">Full year</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="options-group" v-if="plugins.enabled.topics">
|
||||
<h4>{{ plugins.descriptions.topics }}</h4>
|
||||
<label>
|
||||
Topics display mode
|
||||
<select v-model="plugins.options['topics.mode']" @change="load">
|
||||
<option value="starred">Starred topics</option>
|
||||
<option value="mastered">Known and mastered technologies</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Topics sorting
|
||||
<select v-model="plugins.options['topics.sort']">
|
||||
<option value="starred">Recently starred by you</option>
|
||||
<option value="stars">Most stars</option>
|
||||
<option value="activity">Recent actity</option>
|
||||
<option value="random">Random</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Number of topics to display
|
||||
<input type="number" v-model="plugins.options['topics.limit']" @change="load">
|
||||
</label>
|
||||
</div>
|
||||
<div class="options-group" v-if="plugins.enabled.projects">
|
||||
<h4>{{ plugins.descriptions.projects }}</h4>
|
||||
<label>
|
||||
Number of projects to display
|
||||
<input type="number" v-model="plugins.options['projects.limit']" min="1" max="100" @change="load">
|
||||
</label>
|
||||
<label>
|
||||
Repositories projects to display (comma separated)
|
||||
<input type="text" v-model="plugins.options['projects.repositories']" @change="load">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
<div class="step">
|
||||
<h2>3. Generate your metrics</h2>
|
||||
<template v-if="!user">
|
||||
Set your username to generate your metrics 🦑
|
||||
</template>
|
||||
<div class="preview-inliner">
|
||||
<template v-if="generated.content">
|
||||
<img class="metrics preview-inline" :src="generated.content" alt="metrics">
|
||||
</template>
|
||||
<template v-else>
|
||||
<img class="metrics preview-inline" :src="templates.placeholder" alt="metrics">
|
||||
</template>
|
||||
<div class="error" v-if="generated.error">An error occurred. Please try again later.</div>
|
||||
</div>
|
||||
<template v-if="user">
|
||||
<button @click="generate" :disabled="generated.pending">{{ generated.pending ? "Working on it :)" : "Generate your metrics !" }}</button>
|
||||
</template>
|
||||
<div class="palette">
|
||||
Generated metrics use transparency and colors which can be read on both light and dark modes, so everyone can see your stats whatever their preferred color scheme !
|
||||
<div class="palettes">
|
||||
<label>
|
||||
<input type="radio" v-model="palette" value="light"> ☀️ Light mode
|
||||
</label>
|
||||
<label>
|
||||
<input type="radio" v-model="palette" value="dark"> 🌙 Night mode
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<h2>4. Embed these metrics on your GitHub profile</h2>
|
||||
For even more features, be sure to checkout <a href="https://github.com/lowlighter/metrics">lowlighter/metrics</a> !
|
||||
<template v-if="user">
|
||||
<h3>4.1 Using <a href="#">{{ window.location.host }}</a></h3>
|
||||
Add the markdown below in your <i>README.md</i> at <a :href="repo">{{ user }}/{{ user }}</a>
|
||||
<div class="code"><Prism language="markdown" :code="embed"></Prism></div>
|
||||
<h3>4. Using <a href="https://github.com/marketplace/actions/github-metrics-as-svg-image">GitHub action</a></h3>
|
||||
Create a new workflow with the following content at <a :href="repo">{{ user }}/{{ user }}</a>
|
||||
<div class="code"><Prism language="yaml" :code="action"></Prism></div>
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Metrics preview -->
|
||||
<section class="preview">
|
||||
<template v-if="generated.content">
|
||||
<img class="metrics" :src="generated.content" alt="metrics">
|
||||
</template>
|
||||
<template v-else>
|
||||
<img class="metrics" :src="templates.placeholder" alt="metrics">
|
||||
</template>
|
||||
<div class="error" v-if="generated.error">An error occurred. Please try again later.</div>
|
||||
</section>
|
||||
</section>
|
||||
</template>
|
||||
<!-- GitHub requests tracker -->
|
||||
<template>
|
||||
<div class="gh-requests">{{ requests.remaining }} GitHub request{{ requests.remaining > 1 ? "s" : "" }} remaining</div>
|
||||
</template>
|
||||
</main>
|
||||
<!-- Scripts -->
|
||||
<script src="/.js/axios.min.js"></script>
|
||||
<script src="/.js/prism.min.js"></script>
|
||||
<script src="/.js/prism.markdown.min.js"></script>
|
||||
<script src="/.js/prism.yaml.min.js"></script>
|
||||
<script src="/.js/ejs.min.js"></script>
|
||||
<script src="/.js/vue.min.js"></script>
|
||||
<script src="/.js/vue.prism.min.js"></script>
|
||||
<script src="/.js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
213
source/app/web/statics/style.css
Normal file
213
source/app/web/statics/style.css
Normal file
@@ -0,0 +1,213 @@
|
||||
/* General */
|
||||
body {
|
||||
font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
main {
|
||||
background-color: #FFFFFF;
|
||||
color: #1B1F23;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 1rem 1.5rem;
|
||||
overflow-x: hidden;
|
||||
transition: background-color .3s;
|
||||
}
|
||||
/* Headlines */
|
||||
h1 {
|
||||
font-size: 1.6rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
h2 {
|
||||
margin: 1.5rem 0 1rem;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
h3 {
|
||||
margin: .5rem 0 .25rem;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
/* Links */
|
||||
a, a:hover, a:visited {
|
||||
color: #0366D6;
|
||||
text-decoration: none;
|
||||
font-style: normal;
|
||||
outline: none;
|
||||
}
|
||||
a:hover {
|
||||
color: #79B8FF;
|
||||
transition: color .4s;
|
||||
cursor: pointer;
|
||||
}
|
||||
/* Inputs */
|
||||
input, button, select {
|
||||
border-radius: .5rem;
|
||||
padding: .25rem .5rem;
|
||||
outline: none;
|
||||
border: 1px solid #E1E4E8;
|
||||
background-color: #FAFBFC;
|
||||
color: #1B1F23;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
input:focus {
|
||||
outline: none;
|
||||
}
|
||||
input[name=user] {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
input[type=text], select, button {
|
||||
min-width: 50%;
|
||||
}
|
||||
option {
|
||||
text-align: center;
|
||||
}
|
||||
label, button {
|
||||
margin: 1rem;
|
||||
}
|
||||
label {
|
||||
padding-right: .25rem;
|
||||
padding-bottom: .125rem;
|
||||
}
|
||||
input[disabled], button[disabled], select[disabled] {
|
||||
opacity: .5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
label:hover {
|
||||
border-radius: .25rem;
|
||||
background-color: #79B8FF50;
|
||||
transition: background-color .4s;
|
||||
cursor: pointer;
|
||||
}
|
||||
/* Generator */
|
||||
.generator {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.generator .step {
|
||||
margin-bottom: 1rem;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
}
|
||||
.generator .steps {
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.generator .preview {
|
||||
display: none;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.generator .preview .metrics {
|
||||
width: 480px;
|
||||
}
|
||||
.generator .preview-inliner {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.generator .preview-inliner .metrics {
|
||||
width: 100%;
|
||||
max-width: 480px;
|
||||
}
|
||||
@media only screen and (min-width: 1180px) {
|
||||
.generator .preview-inliner {
|
||||
display: none;
|
||||
}
|
||||
.generator .preview {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
/* Plugins */
|
||||
.plugins, .palettes {
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.plugins label, .palettes label {
|
||||
margin: 0 1rem;
|
||||
}
|
||||
.options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.options-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.options-group label {
|
||||
margin: 0;
|
||||
}
|
||||
.options-group h4 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
/* Code snippets */
|
||||
.code {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0 .5rem;
|
||||
}
|
||||
.code pre {
|
||||
width: 100%;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
.code .language-markdown {
|
||||
word-break: break-all !important;
|
||||
white-space: pre-wrap !important;
|
||||
}
|
||||
details {
|
||||
width: 100%;
|
||||
}
|
||||
details summary {
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
}
|
||||
/* Color palette */
|
||||
.palette {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
main.dark {
|
||||
background-color: #181A1B;
|
||||
color: #D4D1C5;
|
||||
}
|
||||
.dark a, .dark a:visited {
|
||||
color: #4CACEE;
|
||||
}
|
||||
.dark input, .dark button {
|
||||
color: #D4D1C5;
|
||||
background-color: #1A1C1E;
|
||||
border-color: #373C3E;
|
||||
}
|
||||
.dark .code {
|
||||
background-color: #1A1C1E;
|
||||
}
|
||||
/* Error */
|
||||
.error {
|
||||
color: #721c24;
|
||||
background-color: #f8d7da;
|
||||
padding: .75rem 1.25rem;
|
||||
border: 1px solid #f5c6cb;
|
||||
border-radius: .25rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
/* Github requests */
|
||||
.gh-requests {
|
||||
position: fixed;
|
||||
right: .25rem;
|
||||
bottom: .25rem;
|
||||
font-size: .8rem;
|
||||
}
|
||||
Reference in New Issue
Block a user