mirror of
https://github.com/kremalicious/blog.git
synced 2024-12-22 17:23:50 +01:00
add basic styling
This commit is contained in:
parent
1cd59e0a84
commit
a293c93f5e
@ -9,8 +9,8 @@
|
|||||||
# Basics
|
# Basics
|
||||||
# --------------------
|
# --------------------
|
||||||
|
|
||||||
name: kremalicious
|
title: kremalicious
|
||||||
description: 'Blog of designer & developer Matthias Kretschmann'
|
tagline: 'Blog of designer & developer Matthias Kretschmann'
|
||||||
url: https://kremalicious.com
|
url: https://kremalicious.com
|
||||||
author:
|
author:
|
||||||
name: Matthias Kretschmann
|
name: Matthias Kretschmann
|
||||||
@ -24,8 +24,4 @@ author:
|
|||||||
ether: "0x339dbC44d39bf1961E385ed0Ae88FC6069b87Ea1"
|
ether: "0x339dbC44d39bf1961E385ed0Ae88FC6069b87Ea1"
|
||||||
|
|
||||||
|
|
||||||
# Urls
|
typekitID: msu4qap
|
||||||
# --------------------
|
|
||||||
|
|
||||||
media_url: "https://res.cloudinary.com/kremalicious"
|
|
||||||
|
|
||||||
|
@ -40,14 +40,14 @@ Just adding feature after feature out of dubious reasons (“Your competitors ha
|
|||||||
|
|
||||||
After finding ezeep’s Buddha nature, the next step was to actually create the various elements of our experience and branding, ranging from typography, color, visual style, writing style, interaction models, user flows and more.
|
After finding ezeep’s Buddha nature, the next step was to actually create the various elements of our experience and branding, ranging from typography, color, visual style, writing style, interaction models, user flows and more.
|
||||||
|
|
||||||
<img src="/media/buddha-colorscheme.png" alt="ezeep color scheme">
|
![ezeep color scheme](../media/buddha-colorscheme.png)
|
||||||
|
|
||||||
While being human and friendly sounds like a no-brainer, in the corporate software world, it turns out it isn’t. ezeep’s vivid color scheme, subtle textures, graphics and icons are a visible manifestation of this, tackling the negative perception of printing for our users.
|
While being human and friendly sounds like a no-brainer, in the corporate software world, it turns out it isn’t. ezeep’s vivid color scheme, subtle textures, graphics and icons are a visible manifestation of this, tackling the negative perception of printing for our users.
|
||||||
|
|
||||||
Creating this layer of delight on top of the functional layers is especially crucial in printing. Good design helps making users more forgiving about errors no matter who’s responsible for them. Printers – the little autistic beings they are – just tend to not work from time to time, and a failing device immediately reflects back on our service. If that’s the case the least we can do is make the experience beautiful.
|
Creating this layer of delight on top of the functional layers is especially crucial in printing. Good design helps making users more forgiving about errors no matter who’s responsible for them. Printers – the little autistic beings they are – just tend to not work from time to time, and a failing device immediately reflects back on our service. If that’s the case the least we can do is make the experience beautiful.
|
||||||
|
|
||||||
<img src="/media/buddha-printer.png">
|
![](../media/buddha-printer.png)
|
||||||
|
|
||||||
Paired with helpful and to-the-point copy, this creates a friendly and unifying atmosphere across the whole product, ranging from the web to native apps on Mac, Windows, iOS and Android.
|
Paired with helpful and to-the-point copy, this creates a friendly and unifying atmosphere across the whole product, ranging from the web to native apps on Mac, Windows, iOS and Android.
|
||||||
|
|
||||||
We acknowledge we don’t have all the answers yet or, more precisely, we know what we don’t know. For us the only way to get those answers is by shipping iteration after iteration and learning from them. Feedback rules.
|
We acknowledge we don’t have all the answers yet or, more precisely, we know what we don’t know. For us the only way to get those answers is by shipping iteration after iteration and learning from them. Feedback rules.
|
||||||
|
10
gatsby-browser.js
Normal file
10
gatsby-browser.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
exports.onInitialClientRender = () => {
|
||||||
|
require('./src/styles/base.scss')
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.onClientEntry = () => {
|
||||||
|
// IntersectionObserver polyfill for gatsby-image (Safari, IE)
|
||||||
|
if (typeof window.IntersectionObserver === 'undefined') {
|
||||||
|
require('intersection-observer')
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,13 @@ module.exports = {
|
|||||||
path: path.join(__dirname, 'content', 'media')
|
path: path.join(__dirname, 'content', 'media')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
resolve: 'gatsby-source-filesystem',
|
||||||
|
options: {
|
||||||
|
name: 'posts',
|
||||||
|
path: path.join(__dirname, 'content')
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
resolve: 'gatsby-transformer-remark',
|
resolve: 'gatsby-transformer-remark',
|
||||||
options: {
|
options: {
|
||||||
@ -33,7 +40,8 @@ module.exports = {
|
|||||||
maxWidth: 940,
|
maxWidth: 940,
|
||||||
linkImagesToOriginal: false,
|
linkImagesToOriginal: false,
|
||||||
sizeByPixelDensity: true,
|
sizeByPixelDensity: true,
|
||||||
showCaptions: true
|
showCaptions: true,
|
||||||
|
backgroundColor: '#e7eef4'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'gatsby-remark-smartypants',
|
'gatsby-remark-smartypants',
|
||||||
@ -44,7 +52,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
resolve: 'gatsby-plugin-sass',
|
resolve: 'gatsby-plugin-sass',
|
||||||
options: {
|
options: {
|
||||||
includePaths: [`${__dirname}/node_modules`]
|
includePaths: [`${__dirname}/node_modules`, `${__dirname}/src/styles`]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'gatsby-plugin-react-helmet',
|
'gatsby-plugin-react-helmet',
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
"gatsby-transformer-sharp": "^2.1.1-beta.5",
|
"gatsby-transformer-sharp": "^2.1.1-beta.5",
|
||||||
"gatsby-transformer-yaml": "^2.1.1-beta.2",
|
"gatsby-transformer-yaml": "^2.1.1-beta.2",
|
||||||
"graphql": "^0.13.2",
|
"graphql": "^0.13.2",
|
||||||
|
"intersection-observer": "^0.5.0",
|
||||||
"node-sass": "^4.9.2",
|
"node-sass": "^4.9.2",
|
||||||
"normalize-css": "^2.3.1",
|
"normalize-css": "^2.3.1",
|
||||||
"normalize-opentype.css": "^0.2.4",
|
"normalize-opentype.css": "^0.2.4",
|
||||||
|
53
src/components/Layout.jsx
Normal file
53
src/components/Layout.jsx
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import React, { Fragment } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import { StaticQuery, graphql } from 'gatsby'
|
||||||
|
import Head from './molecules/Head'
|
||||||
|
import styles from './Layout.module.scss'
|
||||||
|
|
||||||
|
const Layout = ({ children, location }) => {
|
||||||
|
return (
|
||||||
|
<StaticQuery
|
||||||
|
query={graphql`
|
||||||
|
query {
|
||||||
|
# the content/meta.yml file
|
||||||
|
contentYaml {
|
||||||
|
title
|
||||||
|
tagline
|
||||||
|
url
|
||||||
|
author {
|
||||||
|
name
|
||||||
|
email
|
||||||
|
uri
|
||||||
|
twitter
|
||||||
|
github
|
||||||
|
facebook
|
||||||
|
googleplus
|
||||||
|
bitcoin
|
||||||
|
ether
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
render={data => {
|
||||||
|
const meta = data.contentYaml
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<Head meta={meta} />
|
||||||
|
|
||||||
|
<main className={styles.screen} location={location}>
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
</Fragment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.propTypes = {
|
||||||
|
children: PropTypes.any.isRequired,
|
||||||
|
location: PropTypes.object.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Layout
|
6
src/components/Layout.module.scss
Normal file
6
src/components/Layout.module.scss
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
@import 'variables';
|
||||||
|
|
||||||
|
.screen {
|
||||||
|
flex: 1;
|
||||||
|
padding: $spacer;
|
||||||
|
}
|
46
src/components/atoms/Typekit.jsx
Normal file
46
src/components/atoms/Typekit.jsx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { StaticQuery, graphql } from 'gatsby'
|
||||||
|
import Helmet from 'react-helmet'
|
||||||
|
|
||||||
|
const TypekitScript = typekitID => (
|
||||||
|
<script>
|
||||||
|
{`
|
||||||
|
(function(d) {
|
||||||
|
var config = {
|
||||||
|
kitId: '${typekitID}',
|
||||||
|
scriptTimeout: 3000,
|
||||||
|
async: true
|
||||||
|
},
|
||||||
|
h=d.documentElement,t=setTimeout(function(){h.className=h.className.replace(/\bwf-loading\b/g,"")+" wf-inactive";},config.scriptTimeout),tk=d.createElement("script"),f=false,s=d.getElementsByTagName("script")[0],a;h.className+=" wf-loading";tk.src='https://use.typekit.net/'+config.kitId+'.js';tk.async=true;tk.onload=tk.onreadystatechange=function(){a=this.readyState;if(f||a&&a!="complete"&&a!="loaded")return;f=true;clearTimeout(t);try{Typekit.load(config)}catch(e){}};s.parentNode.insertBefore(tk,s)
|
||||||
|
})(document);
|
||||||
|
`}
|
||||||
|
</script>
|
||||||
|
)
|
||||||
|
|
||||||
|
const Typekit = () => (
|
||||||
|
<StaticQuery
|
||||||
|
query={graphql`
|
||||||
|
query {
|
||||||
|
contentYaml {
|
||||||
|
typekitID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
render={data => {
|
||||||
|
const { typekitID } = data.contentYaml
|
||||||
|
|
||||||
|
return (
|
||||||
|
typekitID && (
|
||||||
|
<Helmet>
|
||||||
|
<link rel="dns-prefetch" href="https://use.typekit.net/" />
|
||||||
|
<link rel="dns-prefetch" href="https://p.typekit.net/" />
|
||||||
|
|
||||||
|
{TypekitScript(typekitID)}
|
||||||
|
</Helmet>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Typekit
|
28
src/components/molecules/Head.jsx
Normal file
28
src/components/molecules/Head.jsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import React, { Fragment } from 'react'
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import Helmet from 'react-helmet'
|
||||||
|
import Typekit from '../atoms/Typekit'
|
||||||
|
|
||||||
|
const Head = ({ meta }) => {
|
||||||
|
const { title, tagline } = meta
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<Helmet
|
||||||
|
defaultTitle={`${title.toLowerCase()} ¦ ${tagline.toLowerCase()}`}
|
||||||
|
titleTemplate={`%s ¦ ${title.toLowerCase()}`}
|
||||||
|
>
|
||||||
|
<meta name="apple-mobile-web-app-title" content={title.toLowerCase()} />
|
||||||
|
<meta name="theme-color" content="#e7eef4" />
|
||||||
|
</Helmet>
|
||||||
|
|
||||||
|
<Typekit />
|
||||||
|
</Fragment>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Head.propTypes = {
|
||||||
|
meta: PropTypes.object.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Head
|
@ -1,16 +1,17 @@
|
|||||||
import React, { Fragment } from 'react'
|
import React from 'react'
|
||||||
|
import Layout from '../components/Layout'
|
||||||
|
|
||||||
const NotFound = () => (
|
const NotFound = () => (
|
||||||
<Fragment>
|
<Layout location={location}>
|
||||||
<div className="hal-9000" />
|
<div className="hal-9000" />
|
||||||
|
|
||||||
<p className="srverror-title">I am sorry Dave,</p>
|
<p className="srverror-title">I am sorry Dave,</p>
|
||||||
<p className="srverror-text">I am afraid I can NotFound do that.</p>
|
<p className="srverror-text">I am afraid I can not do that.</p>
|
||||||
|
|
||||||
<a href="#" className="js-search-init">
|
<a href="#" className="js-search-init">
|
||||||
How about a nice search?
|
How about a nice search?
|
||||||
</a>
|
</a>
|
||||||
</Fragment>
|
</Layout>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default NotFound
|
export default NotFound
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { Link, graphql } from 'gatsby'
|
import { Link, graphql } from 'gatsby'
|
||||||
|
import Layout from '../components/Layout'
|
||||||
|
|
||||||
const IndexPage = ({ data }) => {
|
const IndexPage = ({ data }) => {
|
||||||
const edges = data.allMarkdownRemark.edges
|
const edges = data.allMarkdownRemark.edges
|
||||||
@ -12,7 +13,11 @@ const IndexPage = ({ data }) => {
|
|||||||
</li>
|
</li>
|
||||||
))
|
))
|
||||||
|
|
||||||
return <ul>{Posts}</ul>
|
return (
|
||||||
|
<Layout location={location}>
|
||||||
|
<ul>{Posts}</ul>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
IndexPage.propTypes = {
|
IndexPage.propTypes = {
|
||||||
|
121
src/styles/base.scss
Normal file
121
src/styles/base.scss
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
@import 'variables';
|
||||||
|
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: $font-size-root;
|
||||||
|
background: $body-background-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: $font-family-base;
|
||||||
|
font-weight: $font-weight-base;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
line-height: $line-height;
|
||||||
|
color: $font-color-base;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
font-feature-settings: 'liga', 'kern';
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
min-height: 100vh;
|
||||||
|
background: $body-background-color;
|
||||||
|
transition: background .6s $easing;
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
background-color: $body-background-color--dark;
|
||||||
|
color: $text-color--dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p,
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
margin: 0 0 $spacer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Headings
|
||||||
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: $font-size-h1;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: $font-size-h2;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: $font-size-h3;
|
||||||
|
}
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: $font-size-h4;
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: $font-size-h5;
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
font-size: $font-size-h6;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
font-family: $font-family-headings;
|
||||||
|
line-height: $line-height-headings;
|
||||||
|
color: $color-headings;
|
||||||
|
font-weight: $font-weight-headings;
|
||||||
|
margin: 0 0 $spacer;
|
||||||
|
letter-spacing: -.02em;
|
||||||
|
|
||||||
|
.dark & {
|
||||||
|
color: $color-headings--dark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Links
|
||||||
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: $brand-cyan;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: .2s ease-out;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
color: lighten($brand-cyan, 10%);
|
||||||
|
transform: translate3d(0, -.1rem, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Media
|
||||||
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
img,
|
||||||
|
video,
|
||||||
|
svg {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#___gatsby {
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
69
src/styles/variables.scss
Normal file
69
src/styles/variables.scss
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
$imageMaxWidth: 940px;
|
||||||
|
$easing: cubic-bezier(.75, 0, .08, 1);
|
||||||
|
|
||||||
|
// Colors
|
||||||
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
$brand-main: #015565;
|
||||||
|
$brand-cyan: #43a699;
|
||||||
|
$brand-main-light: #88bec8;
|
||||||
|
$brand-light: #e7eef4;
|
||||||
|
|
||||||
|
$brand-grey: #6b7f88;
|
||||||
|
$brand-grey-light: lighten($brand-grey, 15%);
|
||||||
|
$brand-grey-dimmed: lighten($brand-grey, 50%);
|
||||||
|
|
||||||
|
// Backgrounds
|
||||||
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
$body-background-color: $brand-light;
|
||||||
|
$body-background-color--dark: darken($brand-grey, 30%);
|
||||||
|
|
||||||
|
// Text Colors
|
||||||
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
$text-color: $brand-grey;
|
||||||
|
$text-color-light: $brand-grey-light;
|
||||||
|
|
||||||
|
$text-color--dark: $brand-grey-light;
|
||||||
|
$text-color-light--dark: $brand-grey;
|
||||||
|
|
||||||
|
// Typography
|
||||||
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
$font-size-root: 18px;
|
||||||
|
|
||||||
|
$font-size-base: 1rem;
|
||||||
|
$font-size-large: 1.2rem;
|
||||||
|
$font-size-small: .8rem;
|
||||||
|
$font-size-mini: .7rem;
|
||||||
|
|
||||||
|
$font-size-h1: 2.5rem;
|
||||||
|
$font-size-h2: 2rem;
|
||||||
|
$font-size-h3: 1.75rem;
|
||||||
|
$font-size-h4: $font-size-large;
|
||||||
|
$font-size-h5: $font-size-base;
|
||||||
|
$font-size-h6: $font-size-small;
|
||||||
|
|
||||||
|
$line-height: 1.5;
|
||||||
|
$line-height-small: 1.1428571429;
|
||||||
|
|
||||||
|
$font-family-base: 'ff-tisa-sans-web-pro', 'Trebuchet MS', 'Helvetica Neue',
|
||||||
|
Helvetica, Arial, sans-serif;
|
||||||
|
$font-weight-base: 400;
|
||||||
|
$font-color-base: $text-color;
|
||||||
|
|
||||||
|
$font-family-monospace: Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||||
|
|
||||||
|
$font-family-headings: 'brandon-grotesque', 'Avenir Next', 'Helvetica Neue',
|
||||||
|
Helvetica, Arial, sans-serif;
|
||||||
|
$font-weight-headings: 500;
|
||||||
|
$line-height-headings: 1.1;
|
||||||
|
|
||||||
|
$color-headings: $brand-main;
|
||||||
|
$color-headings--dark: $brand-main-light;
|
||||||
|
|
||||||
|
// Components spacing
|
||||||
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
$spacer: ($font-size-base * $line-height);
|
@ -2,25 +2,26 @@ import React from 'react'
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import Helmet from 'react-helmet'
|
import Helmet from 'react-helmet'
|
||||||
import { graphql } from 'gatsby'
|
import { graphql } from 'gatsby'
|
||||||
import Image from '../components/Image'
|
import Layout from '../components/Layout'
|
||||||
|
import Image from '../components/atoms/Image'
|
||||||
|
|
||||||
const Post = ({ data }) => {
|
const Post = ({ data }) => {
|
||||||
const { markdownRemark: post } = data
|
const { markdownRemark: post } = data
|
||||||
const { title, image } = post.frontmatter
|
const { title, image } = post.frontmatter
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="blog-post-container">
|
<Layout location={location}>
|
||||||
<Helmet title={title} />
|
<Helmet title={title} />
|
||||||
|
|
||||||
<div className="blog-post">
|
<article className="blog-post">
|
||||||
<h1 className="title">{title}</h1>
|
<h1 className="title">{title}</h1>
|
||||||
<Image fluid={image.childImageSharp.fluid} alt={title} />
|
{image && <Image fluid={image.childImageSharp.fluid} alt={title} />}
|
||||||
<div
|
<div
|
||||||
className="blog-post-content"
|
className="blog-post-content"
|
||||||
dangerouslySetInnerHTML={{ __html: post.html }}
|
dangerouslySetInnerHTML={{ __html: post.html }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</article>
|
||||||
</div>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user