Ind.ie is now Small Technology Foundation.
Commit cdf6db9f authored by Aral Balkan's avatar Aral Balkan

Merge branch 'owner-settings'

parents 6d39dcff 70739f51
......@@ -27,6 +27,6 @@ export default {
.content-filter-toggle.tabs
{
margin-bottom: 1em;
margin-bottom: 1rem;
}
</style>
......@@ -62,7 +62,10 @@ export default {
}
.card-content .profile-name {
/* when profile names are really long, don’t let them break the modal layout, instead break the words and add hyphens */
/*
When profile names are really long, don’t let them break the modal layout,
instead break the words and add hyphens.
*/
-ms-word-break: break-all;
word-break: break-all;
word-break: break-word;
......@@ -71,15 +74,9 @@ export default {
hyphens: auto;
}
/* Override the size of the name and bio as they should be smaller than in the header. */
.profile-name
{
font-size: 2.5em;
}
.profile-bio
{
font-size: 1.25em;
.card-content .profile-bio {
font-size: 1.25rem;
margin: 0.25rem 0;
}
</style>
......@@ -140,10 +140,12 @@ export default {
.profile {
/* Note: the background colour and image are dynamically set on the
header itself, based on the site configuration settings. */
align-items: center;
color: white;
background-size: cover;
/* position relatively so contained items align to this container */
/* Position relatively so contained items align to this container. */
position: relative;
padding: 1rem 1rem 0;
text-align: center;
......@@ -152,59 +154,66 @@ export default {
.profile-information {
background-color: rgba(0,0,0,0.55);
margin-top: 1em;
/* offset background against padding on profile__material */
margin-top: 1rem;
/* Offset background against padding on profile__material. */
margin-right: -1rem;
margin-left: -1rem;
padding: 0.25rem 0;
}
.profile-name {
font-size: 3em;
font-size: 4rem;
/* numbered font weights won’t work in all browsers, will default to bold weight */
/* Numbered font weights won’t work in all browsers, will default to bold weight. */
font-weight: 400;
line-height: 1.2;
margin: 0;
margin: 0.5rem auto 0 auto;
/* Same max-width as on main in default.vue. */
max-width: 45rem;
}
.profile-bio {
margin: 0 auto 0.25em;
max-width: 42em;
font-size: 1.25rem;
margin: 0.25rem auto 1rem auto;
line-height: 1.25;
/* Same max-width as on main in default.vue. */
max-width: 45rem;
}
.profile-image {
/* make image circular with a white border */
border: 0.2em solid white;
/* Make image circular with a white border. */
border: 0.175rem solid white;
border-radius: 50%;
display: block;
height: 10rem;
width: 10rem;
margin-right: auto;
margin-left: auto;
/* do not allow image size to exceed 7.5em */
max-width: 7.5em;
overflow: hidden;
/* if smaller than 12em, scale image to 40% of width of container */
width: 40%;
}
#follow-button {
position: absolute;
top: 1em;
right: 1em;
top: 1rem;
right: 1rem;
}
/* Main navigation */
/* Main navigation. */
nav {
margin-bottom: 1em;
margin-bottom: 1rem;
}
nav.tabs {
/* make navigation tab text bigger (ideally these will be h2s) */
font-size: 1.5em;
/* Make navigation tab text bigger (ideally these should be h2s). */
font-size: 1.5rem;
/* make navigation tabs very tall */
line-height: 2;
/* Make navigation tabs taller. */
line-height: 2.25;
}
.tabs ul {
......@@ -221,11 +230,11 @@ nav.tabs {
parent li and turn off pointer events to disable the link for disabled tabs.
*/
.tabs li.disabled {
cursor:not-allowed;
cursor: not-allowed;
}
.tabs li.disabled > a {
color: lightgray;
pointer-events:none;
pointer-events: none;
}
</style>
<template>
<!-- Buefy docs recommend adding has-modal-card property for better
mobile handling but it makes the modal very wide. Keep an eye on this -->
<b-modal :active.sync='modalIsActive' :canCancel='false' scroll='keep'>
<div class='modal-card' style='width: auto'>
<header class='modal-card-head'>
<p class='modal-card-title'>Welcome to your Indie Site!</p>
</header>
<form @submit.prevent='submitPasswordForm'>
<section class='modal-card-body'>
<div class='instructions'>
<p>To start, please pick a strong password to protect yourself.</p>
<p>Please don’t lose this. Your site will not store your password to protect your privacy and you can’t recover it if you forget it. If possible, generate and store your password using a password manager like <a href='https://1password.com'>1Password</a> or <a href='https://keepass.info'>KeePass</a>.</p>
</div>
<b-field label='Password'>
<div id='password-field' class='control'>
<no-ssr>
<vue-password
placeholder='Choose a strong password'
v-model='password'
classes='input'
:disabled='isLoading || registrationIsSuccessful'
@strength='validatePasswordStrength'
>
<template slot='password-toggle' slot-scope='props'>
<button
class='button VuePassword__Toggle'
type='button'
@click='props.toggle'
:disabled='isLoading || registrationIsSuccessful'
>{{ props.type === 'password' ? 'Show' : 'Hide' }}</button>
</template>
</vue-password>
</no-ssr>
</div>
</b-field>
</section>
<footer class='modal-card-foot'>
<button :class='setPasswordButtonClasses' type='submit' :disabled='!passwordIsStrongEnough || isLoading || registrationIsSuccessful'>
<span v-if='registrationIsSuccessful' id='success-icon' class='icon is-medium'><i class='fa fa-check'></i></span>
{{ setPasswordButtonText }}</button>
</footer>
</form>
</div>
</b-modal>
</template>
<script>
import vuePassword from '~/components/vuePassword'
export default {
props: {
isActive: {
type: Boolean,
required: true,
default: false
}
},
components: {
vuePassword
},
data () {
return {
password: '',
passwordIsStrongEnough: false,
isLoading: false,
registrationIsSuccessful: false
}
},
computed: {
// Use a computed property so we don’t bind :active.sync to the
// isActive prop directly (as Vue complains about props if they’re
// written to from within components).
modalIsActive: {
get: function () { return this.isActive },
set: function () { /* do nothing; required to silence Vue warning */ }
},
setPasswordButtonText () {
let text = this.registrationIsSuccessful ? 'Done' : 'Set password'
if (this.isLoading) text = 'Registering'
return text
},
setPasswordButtonClasses () {
let classes = {
'button': true,
'is-fullwidth': true,
}
classes['is-success'] = this.registrationIsSuccessful
classes['is-primary'] = !this.registrationIsSuccessful
classes['is-loading'] = this.isLoading
return classes
},
configured: {
get () { return this.$store.state.configured },
set (value) { this.$store.commit('configured', value) }
},
signedIn: {
get () { return this.$store.state.signedIn },
set (value) { this.$store.commit('signedIn', value) }
}
},
methods: {
onClose () {
this.$emit('close')
},
// Called when the input in the password form changes with the current strength.
validatePasswordStrength (strength) {
// We will only accept passwords that are “strong” or “very strong” on
// the zxcvbn scale.
this.passwordIsStrongEnough = (strength.score >= 3)
},
submitPasswordForm () {
console.log('⚠️ Settings screen password form submit is currently unimplemented.')
this.isLoading = true
// Mock a successful registration.
setTimeout(() => {
this.isLoading = false
this.registrationIsSuccessful = true
// After the person has had a chance to see that the registration
// was successful, remove the modal dialog.
setTimeout(() => {
this.signedIn = true
this.configured = true
}, 1000);
}, 1250);
}
}
}
</script>
<style>
.button {
/* Fix the text centering in the button. */
padding-top: 0.15em;
}
/* Put a min-width on the Show/Hide password toggle button in the Settings
tab so that it doesn’t jump around due to the differing amount of space
taken up by the different labels. The class name is set by the component
and has other styles that act on it so do not change that. */
button.button.VuePassword__Toggle {
min-width: 80px;
}
.instructions {
margin-top: 1.5em;
margin-bottom: 1.5em;
}
.instructions p:first-of-type {
font-weight: bold;
}
div.VuePassword__Message {
min-height: 2rem;
}
.VuePassword__Meter {
margin-top: .5rem;
}
.VuePassword__Message {
padding-top: .5rem;
}
#password-field {
margin-bottom: 0;
}
#success-icon {
/* display: inline-block; */
margin-right: 0.25em;
}
</style>
<template>
<div>
<form @submit.prevent>
<b-field label='Name'>
<b-input v-model='name' placeholder='Anonymous'></b-input>
</b-field>
<b-field label='Bio'>
<b-input v-model='bio' placeholder='Anonymous'></b-input>
</b-field>
<label class='label' for='profile-image-upload'>Profile image</label>
<b-field>
<img :src='profileImage' class='profile-image-preview' />
<input id='profile-image-upload' type='file' />
</b-field>
<label class='label' for='background-image-upload'>Background image</label>
<b-field>
<img :src='backgroundImage || "/not-available.png"' :alt='backgroundImage ? "Preview of background image" : "No background image set"' class='background-image-preview' />
<input id='background-image-upload' type='file' />
</b-field>
<label class='label' for='background-colour-input'>Background colour</label>
<b-field>
<div class='background-colour' :style='{ backgroundColor: backgroundColour }'></div>
<vue-color-compact v-if='!backgroundImage' v-model='backgroundColour' />
<span v-if='backgroundImage'>(Hidden by the background image.)</span>
</b-field>
</form>
<!-- Buefy docs recommend adding has-modal-card property for better
mobile handling but it makes the modal very wide. Keep an eye on this -->
<b-modal :active.sync='modalIsActive' :canCancel='false' scroll='keep'>
<div class='modal-card' style='width: auto'>
<header class='modal-card-head'>
<p class='modal-card-title'>Welcome to your Indie Site!</p>
</header>
<form @submit.prevent='submitPasswordForm'>
<section class='modal-card-body'>
<div class='instructions'>
<p>To start, please pick a strong password to protect yourself.</p>
<p>Please don’t lose this. Your site will not store your password to protect your privacy and you can’t recover it if you forget it. If possible, generate and store your password using a password manager like <a href='https://1password.com'>1Password</a> or <a href='https://keepass.info'>KeePass</a>.</p>
</div>
<b-field label='Password'>
<div id='password-field' class='control'>
<no-ssr>
<vue-password
placeholder='Choose a strong password'
v-model='password'
classes='input'
:disabled='isLoading || registrationIsSuccessful'
@strength='validatePasswordStrength'
>
<template slot='password-toggle' slot-scope='props'>
<button
class='button VuePassword__Toggle'
type='button'
@click='props.toggle'
:disabled='isLoading || registrationIsSuccessful'
>{{ props.type === 'password' ? 'Show' : 'Hide' }}</button>
</template>
</vue-password>
</no-ssr>
</div>
</b-field>
</section>
<footer class="modal-card-foot">
<button :class='setPasswordButtonClasses' type='submit' :disabled='!passwordIsStrongEnough || isLoading || registrationIsSuccessful'>
<span v-if='registrationIsSuccessful' id='success-icon' class='icon is-medium'><i class='fa fa-check'></i></span>
{{ setPasswordButtonText }}</button>
</footer>
</form>
</div>
</b-modal>
</div>
</template>
<script>
import vuePassword from '~/components/vuePassword'
import vueColorCompact from '~/../node_modules/vue-color/src/components/Compact.vue'
export default {
components: {
vueColorCompact,
vuePassword
},
computed: {
modalIsActive () { return !this.configured },
setPasswordButtonText () {
let text = this.registrationIsSuccessful ? 'Done' : 'Set password'
if (this.isLoading) text = 'Registering'
return text
},
setPasswordButtonClasses () {
let classes = {
'button': true,
'is-fullwidth': true,
}
classes['is-success'] = this.registrationIsSuccessful
classes['is-primary'] = !this.registrationIsSuccessful
classes['is-loading'] = this.isLoading
return classes
},
name: {
get () { return this.$store.state.name },
set (value) { this.$store.commit('name', value) }
},
bio: {
get () { return this.$store.state.bio },
set (value) { this.$store.commit('bio', value) }
},
profileImage: {
get () { return this.$store.state.profileImage },
set (value) { this.$store.commit('profileImage', value) }
},
backgroundImage: {
get () { return this.$store.state.backgroundImage },
set (value) { this.$store.commit('backgroundImage', value) }
},
backgroundColour: {
get () { return this.$store.state.backgroundColour },
set (value) { this.$store.commit('backgroundColour', value)
// Very basic example of theming based on background colour.
// TODO: Refactor into a more robust, global solution.
// (See default.vue layout for redundancy)
let style = document.createElement('style')
document.head.appendChild(style)
let sheet = style.sheet
console.log('Background colour: ' + value.hex)
sheet.insertRule(`.tabs li.is-active a { color: ${value.hex}; border-bottom-color: ${value.hex}; }`)
sheet.insertRule(`.button.is-primary { background-color: ${value.hex}; }`)
sheet.insertRule(`.button.is-primary:hover { background-color: ${value.hex}; }`)
}
},
configured: {
get () { return this.$store.state.configured },
set (value) { this.$store.commit('configured', value) }
},
signedIn: {
get () { return this.$store.state.signedIn },
set (value) { this.$store.commit('signedIn', value) }
}
},
data () {
return {
password: '',
passwordIsStrongEnough: false,
isLoading: false,
registrationIsSuccessful: false
}
},
methods: {
// Called when the input in the password form changes with the current strength.
validatePasswordStrength (strength) {
// We will only accept passwords that are “strong” or “very strong” on
// the zxcvbn scale.
this.passwordIsStrongEnough = (strength.score >= 3)
},
submitPasswordForm () {
console.log('⚠️ Settings screen password form submit is currently unimplemented.')
this.isLoading = true
// Mock a successful registration.
setTimeout(() => {
this.isLoading = false
this.registrationIsSuccessful = true
// After the person has had a chance to see that the registration
// was successful, remove the modal dialog.
setTimeout(() => {
this.signedIn = true
this.configured = true
}, 1000);
}, 1250);
}
}
}
</script>
<style>
.background-colour {
width: 100px;
height: 65px;
margin-right: .75em;
border: 1px solid #333;
}
.background-image-preview {
width: 100px;
height: 65px;
margin-right: .75em;
border: 1px solid #333;
}
.button {
/* Fix the text centering in the button. */
padding-top: 0.15em;
}
/* Put a min-width on the Show/Hide password toggle button in the Settings
tab so that it doesn’t jump around due to the differing amount of space
taken up by the different labels. The class name is set by the component
and has other styles that act on it so do not change that. */
button.button.VuePassword__Toggle {
min-width: 80px;
}
.instructions {
margin-top: 1.5em;
margin-bottom: 1.5em;
}
.instructions p:first-of-type {
font-weight: bold;
}
div.control {
margin-bottom: 1em;
}
div.card-content {
padding-top: 1em;
}
.modal-card-title {
margin: 0;
}
.modal-card-body {
padding-top: 0;
/* padding-bottom: 0; */
}
div.vc-compact {
width: 246px;
}
div.VuePassword__Message {
min-height: 2rem;
}
.VuePassword__Meter {
margin-top: .5rem;
}
.VuePassword__Message {
padding-top: .5rem;
}
#password-field {
margin-bottom: 0;
}
.profile-image-preview {
width: 100px;
height: 100px;
margin-right: .75em;
border: 1px solid #333;
}
#success-icon {
/* display: inline-block; */
margin-right: 0.25em;
}
</style>
......@@ -31,7 +31,7 @@ export default {
editorContent: this.content || '<p><br></p>',
editorHasContentToSubmit: false,
editorOption: {
placeholder: 'What’s on your mind?',
placeholder: 'What would you like to share publicly?',
theme: 'snow',
modules: {
markdownShortcuts: {},
......@@ -87,40 +87,47 @@ export default {
</script>
<style>
.compose
{
margin-bottom: 1em;
.compose {
margin-bottom: 1rem;
}
.compose-tools
{
/* override Bulma default for .buttons to align to right */
.compose-tools {
/* Override Bulma default for .buttons to align to right. */
justify-content: flex-end;
}
.quill-editor
{
/* make editor window full-width by default */
.quill-editor {
/* Make editor window full-width by default. */
margin-right: -1rem;
margin-left: -1rem;
margin-bottom: 1em;
margin-bottom: 1rem;
}
.ql-editor
{
.ql-editor {
padding-top: 0;
}
.ql-container
{
/* reset so doesn’t use px for font size */
font-size: 1em;
.ql-editor p {
line-height: 2.25rem; /* 36px @ 16px root em */
margin: 1.5rem 0;
}
/* The editor only has a top and bottom border to mark its boundaries. Otherwise, it is styled exactly like the rest of the content to underscore its purpose. When a post is submitted, the minimal chrome around the editor simply fades away and the content becomes part of the page. */
.ql-container {
/* Overwrite so that it doesn’t use px for font size. */
font-family: 'Domine', sans-serif;
font-size: 1.25rem; /* 20px @ 16px root em */
hyphens: auto;
-webkit-hyphens: auto;
}
/*
The editor only has a top and bottom border to mark its boundaries. Otherwise,
it is styled exactly like the rest of the content to underscore its purpose.
When a post is submitted, the minimal chrome around the editor simply fades away
and the content becomes part of the page.
*/
.ql-container.ql-snow
{
.ql-container.ql-snow {
border-right: none;
border-left: none;
}
......
......@@ -52,7 +52,7 @@
}
.VuePassword input {
padding-right: 2.5em;
padding-right: 2.5rem;
width: 100%;
}
......@@ -69,8 +69,8 @@
.VuePassword__Toggle__Icon {
fill: currentColor;
height: 100%;
width: 1.5em;
margin-right: .5em;
width: 1.5rem;
margin-right: 0.5rem;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
......@@ -80,10 +80,10 @@
.VuePassword__Meter {
color: rgb(175, 175, 175);
display: block;
height: .5rem;
margin-top: .2rem;
padding-left: .5rem;
padding-right: .5rem;
height: 0.5rem;
margin-top: 0.2rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
width: 100%;
}