Update Timeline component

This commit is contained in:
Daniel Supernault 2023-07-30 04:04:49 -06:00
parent 3b885709b8
commit 8efb4047b1
No known key found for this signature in database
GPG key ID: 0DEF1C662C9033F7
3 changed files with 658 additions and 516 deletions

View file

@ -1,348 +1,382 @@
<template> <template>
<div class="card-header border-0" style="border-top-left-radius: 15px;border-top-right-radius: 15px;"> <div>
<div class="media align-items-center"> <div v-if="isReblog" class="card-header bg-light border-0" style="border-top-left-radius: 15px;border-top-right-radius: 15px;">
<a :href="status.account.url" @click.prevent="goToProfile()" style="margin-right: 10px;"> <div class="media align-items-center" style="height:10px;">
<img :src="getStatusAvatar()" style="border-radius:15px;" width="44" height="44" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=0';"> <a :href="reblogAccount.url" class="mx-2" @click.prevent="goToProfileById(reblogAccount.id)">
</a> <img :src="reblogAccount.avatar" style="border-radius:10px;" width="24" height="24" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=0';">
</a>
<div style="font-size:12px;font-weight:bold">
<i class="far fa-retweet text-warning mr-1"></i> Reblogged by <a :href="reblogAccount.url" class="text-dark" @click.prevent="goToProfileById(reblogAccount.id)">&commat;{{ reblogAccount.acct }}</a>
</div>
</div>
</div>
<div class="card-header border-0" style="border-top-left-radius: 15px;border-top-right-radius: 15px;">
<div class="media align-items-center">
<a :href="status.account.url" @click.prevent="goToProfile()" style="margin-right: 10px;">
<img :src="getStatusAvatar()" style="border-radius:15px;" width="44" height="44" onerror="this.onerror=null;this.src='/storage/avatars/default.png?v=0';">
</a>
<div class="media-body"> <div class="media-body">
<p class="font-weight-bold username"> <p class="font-weight-bold username">
<a :href="status.account.url" class="text-dark" :id="'apop_'+status.id" @click.prevent="goToProfile"> <a :href="status.account.url" class="text-dark" :id="'apop_'+status.id" @click.prevent="goToProfile">
{{ status.account.acct }} {{ status.account.acct }}
</a> </a>
<b-popover :target="'apop_'+status.id" triggers="hover" placement="bottom" custom-class="shadow border-0 rounded-px"> <b-popover :target="'apop_'+status.id" triggers="hover" placement="bottom" custom-class="shadow border-0 rounded-px">
<profile-hover-card <profile-hover-card
:profile="status.account" :profile="status.account"
v-on:follow="follow" v-on:follow="follow"
v-on:unfollow="unfollow" /> v-on:unfollow="unfollow" />
</b-popover> </b-popover>
</p> </p>
<p class="text-lighter mb-0" style="font-size: 13px;"> <p class="text-lighter mb-0" style="font-size: 13px;">
<span v-if="status.account.is_admin" class="d-none d-md-inline-block"> <span v-if="status.account.is_admin" class="d-none d-md-inline-block">
<span class="badge badge-light text-danger user-select-none" title="Admin account">ADMIN</span> <span class="badge badge-light text-danger user-select-none" title="Admin account">ADMIN</span>
<span class="mx-1 text-lighter">·</span> <span class="mx-1 text-lighter">·</span>
</span> </span>
<a class="timestamp text-lighter" :href="status.url" @click.prevent="goToPost()" :title="status.created_at"> <a class="timestamp text-lighter" :href="status.url" @click.prevent="goToPost()" :title="status.created_at">
{{ timeago(status.created_at) }} {{ timeago(status.created_at) }}
</a> </a>
<span v-if="config.ab.pue && status.hasOwnProperty('edited_at') && status.edited_at"> <span v-if="config.ab.pue && status.hasOwnProperty('edited_at') && status.edited_at">
<span class="mx-1 text-lighter">·</span> <span class="mx-1 text-lighter">·</span>
<a class="text-lighter" href="#" @click.prevent="openEditModal">Edited</a> <a class="text-lighter" href="#" @click.prevent="openEditModal">Edited</a>
</span> </span>
<span class="mx-1 text-lighter">·</span> <span class="mx-1 text-lighter">·</span>
<span class="visibility text-lighter" :title="scopeTitle(status.visibility)"><i :class="scopeIcon(status.visibility)"></i></span> <span class="visibility text-lighter" :title="scopeTitle(status.visibility)"><i :class="scopeIcon(status.visibility)"></i></span>
<span v-if="status.place && status.place.hasOwnProperty('name')" class="d-none d-md-inline-block"> <span v-if="status.place && status.place.hasOwnProperty('name')" class="d-none d-md-inline-block">
<span class="mx-1 text-lighter">·</span> <span class="mx-1 text-lighter">·</span>
<span class="location text-lighter"><i class="far fa-map-marker-alt"></i> {{ status.place.name }}, {{ status.place.country }}</span> <span class="location text-lighter"><i class="far fa-map-marker-alt"></i> {{ status.place.name }}, {{ status.place.country }}</span>
</span> </span>
</p> </p>
</div> </div>
<button v-if="!useDropdownMenu" class="btn btn-link text-lighter" @click="openMenu"> <button v-if="!useDropdownMenu" class="btn btn-link text-lighter" @click="openMenu">
<i class="far fa-ellipsis-v fa-lg"></i> <i class="far fa-ellipsis-v fa-lg"></i>
</button> </button>
<b-dropdown <b-dropdown
v-else v-else
no-caret no-caret
right right
variant="link" variant="link"
toggle-class="text-lighter" toggle-class="text-lighter"
html="<i class='far fa-ellipsis-v fa-lg px-3'></i>" html="<i class='far fa-ellipsis-v fa-lg px-3'></i>"
> >
<b-dropdown-item> <b-dropdown-item>
<p class="mb-0 font-weight-bold">{{ $t('menu.viewPost') }}</p> <p class="mb-0 font-weight-bold">{{ $t('menu.viewPost') }}</p>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item> <b-dropdown-item>
<p class="mb-0 font-weight-bold">{{ $t('common.copyLink') }}</p> <p class="mb-0 font-weight-bold">{{ $t('common.copyLink') }}</p>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item v-if="status.local"> <b-dropdown-item v-if="status.local">
<p class="mb-0 font-weight-bold">{{ $t('menu.embed') }}</p> <p class="mb-0 font-weight-bold">{{ $t('menu.embed') }}</p>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-divider v-if="!owner"></b-dropdown-divider> <b-dropdown-divider v-if="!owner"></b-dropdown-divider>
<b-dropdown-item v-if="!owner"> <b-dropdown-item v-if="!owner">
<p class="mb-0 font-weight-bold">{{ $t('menu.report') }}</p> <p class="mb-0 font-weight-bold">{{ $t('menu.report') }}</p>
<p class="small text-muted mb-0">Report content that violate our rules</p> <p class="small text-muted mb-0">Report content that violate our rules</p>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item v-if="!owner && status.hasOwnProperty('relationship')"> <b-dropdown-item v-if="!owner && status.hasOwnProperty('relationship')">
<p class="mb-0 font-weight-bold">{{ status.relationship.muting ? 'Unmute' : 'Mute' }}</p> <p class="mb-0 font-weight-bold">{{ status.relationship.muting ? 'Unmute' : 'Mute' }}</p>
<p class="small text-muted mb-0">Hide posts from this account in your feeds</p> <p class="small text-muted mb-0">Hide posts from this account in your feeds</p>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item v-if="!owner && status.hasOwnProperty('relationship')"> <b-dropdown-item v-if="!owner && status.hasOwnProperty('relationship')">
<p class="mb-0 font-weight-bold text-danger">{{ status.relationship.blocking ? 'Unblock' : 'Block' }}</p> <p class="mb-0 font-weight-bold text-danger">{{ status.relationship.blocking ? 'Unblock' : 'Block' }}</p>
<p class="small text-muted mb-0">Restrict all content from this account</p> <p class="small text-muted mb-0">Restrict all content from this account</p>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-divider v-if="owner || admin"></b-dropdown-divider> <b-dropdown-divider v-if="owner || admin"></b-dropdown-divider>
<b-dropdown-item v-if="owner || admin"> <b-dropdown-item v-if="owner || admin">
<p class="mb-0 font-weight-bold text-danger"> <p class="mb-0 font-weight-bold text-danger">
{{ $t('common.delete') }} {{ $t('common.delete') }}
</p> </p>
</b-dropdown-item> </b-dropdown-item>
</b-dropdown> </b-dropdown>
</div> </div>
<edit-history-modal ref="editModal" :status="status" /> <edit-history-modal ref="editModal" :status="status" />
</div> </div>
</div>
</template> </template>
<script type="text/javascript"> <script type="text/javascript">
import ProfileHoverCard from './../profile/ProfileHoverCard.vue'; import ProfileHoverCard from './../profile/ProfileHoverCard.vue';
import EditHistoryModal from './EditHistoryModal.vue'; import EditHistoryModal from './EditHistoryModal.vue';
export default { export default {
props: { props: {
status: { status: {
type: Object type: Object
}, },
profile: { profile: {
type: Object type: Object
}, },
useDropdownMenu: { useDropdownMenu: {
type: Boolean, type: Boolean,
default: false default: false
} },
},
components: { isReblog: {
"profile-hover-card": ProfileHoverCard, type: Boolean,
"edit-history-modal": EditHistoryModal default: false
}, },
data() { reblogAccount: {
return { type: Object
config: window.App.config, }
menuLoading: true, },
owner: false,
admin: false,
license: false
}
},
methods: { components: {
timeago(ts) { "profile-hover-card": ProfileHoverCard,
let short = App.util.format.timeAgo(ts); "edit-history-modal": EditHistoryModal
if( },
short.endsWith('s') ||
short.endsWith('m') ||
short.endsWith('h')
) {
return short;
}
const intl = new Intl.DateTimeFormat(undefined, {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
});
return intl.format(new Date(ts));
},
openMenu() { data() {
this.$emit('menu'); return {
}, config: window.App.config,
menuLoading: true,
owner: false,
admin: false,
license: false
}
},
scopeIcon(scope) { methods: {
switch(scope) { timeago(ts) {
case 'public': let short = App.util.format.timeAgo(ts);
return 'far fa-globe'; if(
break; short.endsWith('s') ||
short.endsWith('m') ||
short.endsWith('h')
) {
return short;
}
const intl = new Intl.DateTimeFormat(undefined, {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: 'numeric'
});
return intl.format(new Date(ts));
},
case 'unlisted': openMenu() {
return 'far fa-lock-open'; this.$emit('menu');
break; },
case 'private': scopeIcon(scope) {
return 'far fa-lock'; switch(scope) {
break; case 'public':
return 'far fa-globe';
break;
default: case 'unlisted':
return 'far fa-globe'; return 'far fa-lock-open';
break; break;
}
},
scopeTitle(scope) { case 'private':
switch(scope) { return 'far fa-lock';
case 'public': break;
return 'Visible to everyone';
break;
case 'unlisted': default:
return 'Hidden from public feeds'; return 'far fa-globe';
break; break;
}
},
case 'private': scopeTitle(scope) {
return 'Only visible to followers'; switch(scope) {
break; case 'public':
return 'Visible to everyone';
break;
default: case 'unlisted':
return ''; return 'Hidden from public feeds';
break; break;
}
},
goToPost() { case 'private':
if(location.pathname.split('/').pop() == this.status.id) { return 'Only visible to followers';
location.href = this.status.local ? this.status.url + '?fs=1' : this.status.url; break;
return;
}
this.$router.push({ default:
name: 'post', return '';
path: `/i/web/post/${this.status.id}`, break;
params: { }
id: this.status.id, },
cachedStatus: this.status,
cachedProfile: this.profile
}
})
},
goToProfile() { goToPost() {
this.$nextTick(() => { if(location.pathname.split('/').pop() == this.status.id) {
this.$router.push({ location.href = this.status.local ? this.status.url + '?fs=1' : this.status.url;
name: 'profile', return;
path: `/i/web/profile/${this.status.account.id}`, }
params: {
id: this.status.account.id,
cachedProfile: this.status.account,
cachedUser: this.profile
}
});
});
},
toggleContentWarning() { this.$router.push({
this.key++; name: 'post',
this.sensitive = true; path: `/i/web/post/${this.status.id}`,
this.status.sensitive = !this.status.sensitive; params: {
}, id: this.status.id,
cachedStatus: this.status,
cachedProfile: this.profile
}
})
},
like() { goToProfileById(id) {
event.currentTarget.blur(); this.$nextTick(() => {
if(this.status.favourited) { this.$router.push({
this.$emit('unlike'); name: 'profile',
} else { path: `/i/web/profile/${id}`,
this.$emit('like'); params: {
} id: id,
}, cachedUser: this.profile
}
});
});
},
toggleMenu(bvEvent) { goToProfile() {
setTimeout(() => { this.$nextTick(() => {
this.menuLoading = false; this.$router.push({
}, 500); name: 'profile',
}, path: `/i/web/profile/${this.status.account.id}`,
params: {
id: this.status.account.id,
cachedProfile: this.status.account,
cachedUser: this.profile
}
});
});
},
closeMenu(bvEvent) { toggleContentWarning() {
setTimeout(() => { this.key++;
bvEvent.target.parentNode.firstElementChild.blur(); this.sensitive = true;
}, 100); this.status.sensitive = !this.status.sensitive;
}, },
showLikes() { like() {
event.currentTarget.blur(); event.currentTarget.blur();
this.$emit('likes-modal'); if(this.status.favourited) {
}, this.$emit('unlike');
} else {
this.$emit('like');
}
},
showShares() { toggleMenu(bvEvent) {
event.currentTarget.blur(); setTimeout(() => {
this.$emit('shares-modal'); this.menuLoading = false;
}, }, 500);
},
showComments() { closeMenu(bvEvent) {
event.currentTarget.blur(); setTimeout(() => {
this.showCommentDrawer = !this.showCommentDrawer; bvEvent.target.parentNode.firstElementChild.blur();
}, }, 100);
},
copyLink() { showLikes() {
event.currentTarget.blur(); event.currentTarget.blur();
App.util.clipboard(this.status.url); this.$emit('likes-modal');
}, },
shareToOther() { showShares() {
if (navigator.canShare) { event.currentTarget.blur();
navigator.share({ this.$emit('shares-modal');
url: this.status.url },
})
.then(() => console.log('Share was successful.'))
.catch((error) => console.log('Sharing failed', error));
} else {
swal('Not supported', 'Your current device does not support native sharing.', 'error');
}
},
counterChange(type) { showComments() {
this.$emit('counter-change', type); event.currentTarget.blur();
}, this.showCommentDrawer = !this.showCommentDrawer;
},
showCommentLikes(post) { copyLink() {
this.$emit('comment-likes-modal', post); event.currentTarget.blur();
}, App.util.clipboard(this.status.url);
},
shareStatus() { shareToOther() {
this.$emit('share'); if (navigator.canShare) {
}, navigator.share({
url: this.status.url
})
.then(() => console.log('Share was successful.'))
.catch((error) => console.log('Sharing failed', error));
} else {
swal('Not supported', 'Your current device does not support native sharing.', 'error');
}
},
unshareStatus() { counterChange(type) {
this.$emit('unshare'); this.$emit('counter-change', type);
}, },
handleReport(post) { showCommentLikes(post) {
this.$emit('handle-report', post); this.$emit('comment-likes-modal', post);
}, },
follow() { shareStatus() {
this.$emit('follow'); this.$emit('share');
}, },
unfollow() { unshareStatus() {
this.$emit('unfollow'); this.$emit('unshare');
}, },
handleReblog() { handleReport(post) {
this.isReblogging = true; this.$emit('handle-report', post);
if(this.status.reblogged) { },
this.$emit('unshare');
} else {
this.$emit('share');
}
setTimeout(() => { follow() {
this.isReblogging = false; this.$emit('follow');
}, 5000); },
},
handleBookmark() { unfollow() {
event.currentTarget.blur(); this.$emit('unfollow');
this.isBookmarking = true; },
this.$emit('bookmark');
setTimeout(() => { handleReblog() {
this.isBookmarking = false; this.isReblogging = true;
}, 5000); if(this.status.reblogged) {
}, this.$emit('unshare');
} else {
this.$emit('share');
}
getStatusAvatar() { setTimeout(() => {
if(window._sharedData.user.id == this.status.account.id) { this.isReblogging = false;
return window._sharedData.user.avatar; }, 5000);
} },
return this.status.account.avatar; handleBookmark() {
}, event.currentTarget.blur();
this.isBookmarking = true;
this.$emit('bookmark');
openModTools() { setTimeout(() => {
this.$emit('mod-tools'); this.isBookmarking = false;
}, }, 5000);
},
openEditModal() { getStatusAvatar() {
this.$refs.editModal.open(); if(window._sharedData.user.id == this.status.account.id) {
} return window._sharedData.user.avatar;
} }
}
return this.status.account.avatar;
},
openModTools() {
this.$emit('mod-tools');
},
openEditModal() {
this.$refs.editModal.open();
}
}
}
</script> </script>

View file

@ -8,6 +8,30 @@
</div> </div>
<div v-else> <div v-else>
<transition name="fade">
<div v-if="showReblogBanner && getScope() === 'home'" class="card bg-g-amin card-body shadow-sm mb-3" style="border-radius: 15px;">
<div class="d-flex justify-content-around align-items-center">
<div class="flex-grow-1 ft-std">
<h2 class="font-weight-bold text-white mb-0">Introducing Reblogs in feeds</h2>
<hr />
<p class="lead text-white mb-0">
See reblogs from accounts you follow in your home feed!
</p>
<p class="text-white small mb-1" style="opacity:0.6">
You can disable reblogs in feeds on the Timeline Settings page.
</p>
<hr />
<div class="d-flex">
<button class="btn btn-light rounded-pill font-weight-bold btn-block mr-2" @click.prevent="enableReblogs()">
<template v-if="!enablingReblogs">Show reblogs in home feed</template>
<b-spinner small v-else />
</button>
<button class="btn btn-outline-light rounded-pill font-weight-bold px-5" @click.prevent="hideReblogs()">Hide</button>
</div>
</div>
</div>
</div>
</transition>
<status <status
v-for="(status, index) in feed" v-for="(status, index) in feed"
:key="'pf_feed:' + status.id + ':idx:' + index + ':fui:' + forceUpdateIdx" :key="'pf_feed:' + status.id + ':idx:' + index + ':fui:' + forceUpdateIdx"
@ -140,6 +164,7 @@
data() { data() {
return { return {
settings: [],
isLoaded: false, isLoaded: false,
feed: [], feed: [],
ids: [], ids: [],
@ -159,7 +184,9 @@
reportedStatusId: 0, reportedStatusId: 0,
showSharesModal: false, showSharesModal: false,
sharesModalPost: {}, sharesModalPost: {},
forceUpdateIdx: 0 forceUpdateIdx: 0,
showReblogBanner: false,
enablingReblogs: false
} }
}, },
@ -174,7 +201,7 @@
return; return;
}; };
} }
this.fetchTimeline(); this.fetchSettings();
}, },
methods: { methods: {
@ -194,13 +221,48 @@
} }
}, },
fetchTimeline(scrollToTop = false) { fetchSettings() {
let url = `/api/pixelfed/v1/timelines/${this.getScope()}`; axios.get('/api/pixelfed/v1/web/settings')
axios.get(url, { .then(res => {
params: { this.settings = res.data;
max_id: this.max_id,
limit: 6 if(!res.data) {
this.showReblogBanner = true;
} else {
if(res.data.hasOwnProperty('hide_reblog_banner')) {
} else if(res.data.hasOwnProperty('enable_reblogs')) {
if(!res.data.enable_reblogs) {
this.showReblogBanner = true;
}
} else {
this.showReblogBanner = true;
}
} }
})
.finally(() => {
this.fetchTimeline();
})
},
fetchTimeline(scrollToTop = false) {
let url, params;
if(this.getScope() === 'home' && this.settings && this.settings.hasOwnProperty('enable_reblogs') && this.settings.enable_reblogs) {
url = `/api/v1/timelines/home`;
params = {
'_pe': 1,
max_id: this.max_id,
limit: 6,
include_reblogs: true,
}
} else {
url = `/api/pixelfed/v1/timelines/${this.getScope()}`;
params = {
max_id: this.max_id,
limit: 6,
}
}
axios.get(url, {
params: params
}).then(res => { }).then(res => {
let ids = res.data.map(p => { let ids = res.data.map(p => {
if(p && p.hasOwnProperty('relationship')) { if(p && p.hasOwnProperty('relationship')) {
@ -242,12 +304,24 @@
this.isFetchingMore = true; this.isFetchingMore = true;
let url = `/api/pixelfed/v1/timelines/${this.getScope()}`; let url, params;
axios.get(url, { if(this.getScope() === 'home' && this.settings && this.settings.hasOwnProperty('enable_reblogs') && this.settings.enable_reblogs) {
params: { url = `/api/v1/timelines/home`;
params = {
'_pe': 1,
max_id: this.max_id, max_id: this.max_id,
limit: 6 limit: 6,
include_reblogs: true,
} }
} else {
url = `/api/pixelfed/v1/timelines/${this.getScope()}`;
params = {
max_id: this.max_id,
limit: 6,
}
}
axios.get(url, {
params: params
}).then(res => { }).then(res => {
if(!res.data.length) { if(!res.data.length) {
this.endFeedReached = true; this.endFeedReached = true;
@ -568,7 +642,31 @@
this.$nextTick(() => { this.$nextTick(() => {
this.forceUpdateIdx++; this.forceUpdateIdx++;
}); });
} },
enableReblogs() {
this.enablingReblogs = true;
axios.post('/api/pixelfed/v1/web/settings', {
field: 'enable_reblogs',
value: true
})
.then(res => {
setTimeout(() => {
window.location.reload();
}, 1000);
})
},
hideReblogs() {
this.showReblogBanner = false;
axios.post('/api/pixelfed/v1/web/settings', {
field: 'hide_reblog_banner',
value: true
})
.then(res => {
})
},
}, },
watch: { watch: {

View file

@ -1,166 +1,172 @@
@import "lib/ibmplexsans"; @import "lib/ibmplexsans";
:root { :root {
--light: #fff; --light: #fff;
--dark: #000; --dark: #000;
--body-bg: rgba(243,244,246,1); --body-bg: rgba(243,244,246,1);
--body-color: #212529; --body-color: #212529;
--nav-bg: #fff; --nav-bg: #fff;
--bg-light: #f8f9fa; --bg-light: #f8f9fa;
--primary: #3B82F6; --primary: #3B82F6;
--light-gray: #f8f9fa; --light-gray: #f8f9fa;
--text-lighter: #94a3b8; --text-lighter: #94a3b8;
--card-bg: #fff; --card-bg: #fff;
--light-hover-bg: #f9fafb; --light-hover-bg: #f9fafb;
--btn-light-border: #fff; --btn-light-border: #fff;
--input-border: #e2e8f0; --input-border: #e2e8f0;
--comment-bg: #eff2f5; --comment-bg: #eff2f5;
--border-color: #dee2e6; --border-color: #dee2e6;
--card-header-accent: #f9fafb; --card-header-accent: #f9fafb;
--dropdown-item-hover-bg: #e9ecef; --dropdown-item-hover-bg: #e9ecef;
--dropdown-item-hover-color: #16181b; --dropdown-item-hover-color: #16181b;
--dropdown-item-color: #64748b; --dropdown-item-color: #64748b;
--dropdown-item-active-color: #334155; --dropdown-item-active-color: #334155;
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root { :root {
--light: #000; --light: #000;
--dark: #fff; --dark: #fff;
--body-bg: #000; --body-bg: #000;
--body-color: #9ca3af; --body-color: #9ca3af;
--nav-bg: #000; --nav-bg: #000;
--bg-light: #212124; --bg-light: #212124;
--light-gray: #212124; --light-gray: #212124;
--text-lighter: #818181; --text-lighter: #818181;
--card-bg: #161618; --card-bg: #161618;
--light-hover-bg: #212124; --light-hover-bg: #212124;
--btn-light-border: #161618; --btn-light-border: #161618;
--input-border: #161618; --input-border: #161618;
--comment-bg: #212124; --comment-bg: #212124;
--border-color: #212124; --border-color: #212124;
--card-header-accent: #212124; --card-header-accent: #212124;
--dropdown-item-hover-bg: #000; --dropdown-item-hover-bg: #000;
--dropdown-item-hover-color: #818181; --dropdown-item-hover-color: #818181;
--dropdown-item-color: #64748b; --dropdown-item-color: #64748b;
--dropdown-item-active-color: #fff; --dropdown-item-active-color: #fff;
} }
} }
.force-light-mode { .force-light-mode {
--light: #fff; --light: #fff;
--dark: #000; --dark: #000;
--body-bg: rgba(243,244,246,1); --body-bg: rgba(243,244,246,1);
--body-color: #212529; --body-color: #212529;
--nav-bg: #fff; --nav-bg: #fff;
--bg-light: #f8f9fa; --bg-light: #f8f9fa;
--primary: #3B82F6; --primary: #3B82F6;
--light-gray: #f8f9fa; --light-gray: #f8f9fa;
--text-lighter: #94a3b8; --text-lighter: #94a3b8;
--card-bg: #fff; --card-bg: #fff;
--light-hover-bg: #f9fafb; --light-hover-bg: #f9fafb;
--btn-light-border: #fff; --btn-light-border: #fff;
--input-border: #e2e8f0; --input-border: #e2e8f0;
--comment-bg: #eff2f5; --comment-bg: #eff2f5;
--border-color: #dee2e6; --border-color: #dee2e6;
--card-header-accent: #f9fafb; --card-header-accent: #f9fafb;
--dropdown-item-hover-bg: #e9ecef; --dropdown-item-hover-bg: #e9ecef;
--dropdown-item-hover-color: #16181b; --dropdown-item-hover-color: #16181b;
--dropdown-item-color: #64748b; --dropdown-item-color: #64748b;
--dropdown-item-active-color: #334155; --dropdown-item-active-color: #334155;
} }
.force-dark-mode { .force-dark-mode {
--light: #000; --light: #000;
--dark: #fff; --dark: #fff;
--body-bg: #000; --body-bg: #000;
--body-color: #9ca3af; --body-color: #9ca3af;
--nav-bg: #000; --nav-bg: #000;
--bg-light: #212124; --bg-light: #212124;
--light-gray: #212124; --light-gray: #212124;
--text-lighter: #818181; --text-lighter: #818181;
--card-bg: #161618; --card-bg: #161618;
--light-hover-bg: #212124; --light-hover-bg: #212124;
--btn-light-border: #161618; --btn-light-border: #161618;
--input-border: #161618; --input-border: #161618;
--comment-bg: #212124; --comment-bg: #212124;
--border-color: #212124; --border-color: #212124;
--card-header-accent: #212124; --card-header-accent: #212124;
--dropdown-item-hover-bg: #000; --dropdown-item-hover-bg: #000;
--dropdown-item-hover-color: #818181; --dropdown-item-hover-color: #818181;
--dropdown-item-color: #64748b; --dropdown-item-color: #64748b;
--dropdown-item-active-color: #b3b3b3; --dropdown-item-active-color: #b3b3b3;
} }
body { body {
background: var(--body-bg); background: var(--body-bg);
font-family: 'IBM Plex Sans', sans-serif; font-family: 'IBM Plex Sans', sans-serif;
color: var(--body-color); color: var(--body-color);
} }
.web-wrapper { .web-wrapper {
margin-bottom: 10rem; margin-bottom: 10rem;
} }
.container-fluid { .container-fluid {
max-width: 1440px !important; max-width: 1440px !important;
} }
.jumbotron { .jumbotron {
border-radius: 18px; border-radius: 18px;
} }
.rounded-px { .rounded-px {
border-radius: 18px; border-radius: 18px;
} }
.doc-body { .doc-body {
p:last-child { p:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
} }
.navbar-laravel { .navbar-laravel {
background-color: var(--nav-bg); background-color: var(--nav-bg);
} }
.sticky-top { .sticky-top {
z-index: 2; z-index: 2;
} }
.navbar-light .navbar-brand { .navbar-light .navbar-brand {
color: var(--dark); color: var(--dark);
&:hover { &:hover {
color: var(--dark); color: var(--dark);
} }
} }
.primary { .primary {
color: var(--primary); color: var(--primary);
}
.bg-g-amin {
background: #8E2DE2;
background: -webkit-linear-gradient(to right, #4A00E0, #8E2DE2);
background: linear-gradient(to left, #4A00E0, #8E2DE2);
} }
.text-lighter { .text-lighter {
color: var(--text-lighter) !important; color: var(--text-lighter) !important;
} }
.text-dark { .text-dark {
color: var(--body-color) !important; color: var(--body-color) !important;
&:hover { &:hover {
color: var(--dark) !important; color: var(--dark) !important;
} }
} }
@ -169,16 +175,16 @@ a.text-dark:hover {
} }
.badge-primary { .badge-primary {
background-color: var(--primary); background-color: var(--primary);
} }
.btn-primary { .btn-primary {
background-color: var(--primary); background-color: var(--primary);
color: #fff !important; color: #fff !important;
} }
.btn-outline-light { .btn-outline-light {
border-color: var(--light-gray); border-color: var(--light-gray);
} }
.border { .border {
@ -187,51 +193,51 @@ a.text-dark:hover {
.bg-white, .bg-white,
.bg-light { .bg-light {
background-color: var(--bg-light) !important; background-color: var(--bg-light) !important;
border-color: var(--bg-light) !important; border-color: var(--bg-light) !important;
} }
.btn-light { .btn-light {
background-color: var(--light-gray); background-color: var(--light-gray);
border-color: var(--btn-light-border); border-color: var(--btn-light-border);
color: var(--body-color); color: var(--body-color);
&:hover { &:hover {
color: var(--body-color); color: var(--body-color);
background-color: var(--card-bg); background-color: var(--card-bg);
border-color: var(--btn-light-border); border-color: var(--btn-light-border);
} }
} }
.autocomplete-input { .autocomplete-input {
border: 1px solid var(--light-gray) !important; border: 1px solid var(--light-gray) !important;
color: var(--body-color); color: var(--body-color);
} }
.autocomplete-result-list { .autocomplete-result-list {
background: var(--light) !important; background: var(--light) !important;
z-index: 2 !important; z-index: 2 !important;
} }
.dropdown-menu, .dropdown-menu,
span.twitter-typeahead .tt-menu, span.twitter-typeahead .tt-menu,
.form-control { .form-control {
border: 1px solid var(--border-color) !important; border: 1px solid var(--border-color) !important;
color: var(--body-color); color: var(--body-color);
background-color: var(--card-bg); background-color: var(--card-bg);
} }
.tribute-container li, .tribute-container li,
.dropdown-item, .dropdown-item,
span.twitter-typeahead .tt-suggestion { span.twitter-typeahead .tt-suggestion {
color: var(--body-color); color: var(--body-color);
} }
.dropdown-item:hover, .dropdown-item:hover,
span.twitter-typeahead .tt-suggestion:hover, span.twitter-typeahead .tt-suggestion:hover,
.dropdown-item:focus, .dropdown-item:focus,
span.twitter-typeahead .tt-suggestion:focus { span.twitter-typeahead .tt-suggestion:focus {
color: var(--dropdown-item-hover-color); color: var(--dropdown-item-hover-color);
background-color: var(--dropdown-item-hover-bg); background-color: var(--dropdown-item-hover-bg);
text-decoration: none; text-decoration: none;
} }
@ -245,7 +251,7 @@ span.twitter-typeahead .tt-suggestion:focus {
.card-header, .card-header,
.card-footer, .card-footer,
.ph-item { .ph-item {
background-color: var(--card-bg); background-color: var(--card-bg);
} }
.badge-light, .badge-light,
@ -253,143 +259,147 @@ span.twitter-typeahead .tt-suggestion:focus {
.ph-avatar, .ph-avatar,
.ph-picture, .ph-picture,
.ph-row div { .ph-row div {
background-color: var(--light-gray); background-color: var(--light-gray);
} }
.card-header, .card-header,
.border-top, .border-top,
.border-bottom { .border-bottom {
border-color: var(--border-color) !important; border-color: var(--border-color) !important;
} }
.modal-header, .modal-header,
.modal-footer { .modal-footer {
border-color: var(--border-color); border-color: var(--border-color);
} }
.compose-action:hover { .compose-action:hover {
background-color: var(--light-gray) !important; background-color: var(--light-gray) !important;
} }
.dropdown-divider { .dropdown-divider {
border-color: var(--dropdown-item-hover-bg); border-color: var(--dropdown-item-hover-bg);
} }
.metro-nav { .metro-nav {
&.flex-column { &.flex-column {
background-color: var(--card-bg); background-color: var(--card-bg);
.nav-item { .nav-item {
.nav-link:hover { .nav-link:hover {
background-color: var(--light-hover-bg); background-color: var(--light-hover-bg);
} }
} }
} }
} }
.child-reply-form { .child-reply-form {
.form-control { .form-control {
border-color: var(--input-border); border-color: var(--input-border);
color: var(--body-color); color: var(--body-color);
} }
} }
.ui-menu { .ui-menu {
.btn-group { .btn-group {
.btn:first-child { .btn:first-child {
border-top-left-radius: 50rem; border-top-left-radius: 50rem;
border-bottom-left-radius: 50rem; border-bottom-left-radius: 50rem;
} }
.btn:last-child { .btn:last-child {
border-top-right-radius: 50rem; border-top-right-radius: 50rem;
border-bottom-right-radius: 50rem; border-bottom-right-radius: 50rem;
} }
.btn-primary { .btn-primary {
font-weight: bold; font-weight: bold;
} }
} }
.b-custom-control-lg { .b-custom-control-lg {
padding-bottom: 8px; padding-bottom: 8px;
} }
} }
.content-label { .content-label {
&-wrapper { &-wrapper {
div:not(.content-label) { div:not(.content-label) {
height: 100%; height: 100%;
} }
} }
&-text { &-text {
width: 80%; width: 80%;
@media (min-width: 768px) { @media (min-width: 768px) {
width: 50%; width: 50%;
} }
} }
} }
.compose-modal-component { .compose-modal-component {
.form-control:focus { .form-control:focus {
color: var(--body-color); color: var(--body-color);
} }
} }
.modal-body { .modal-body {
.nav-tabs .nav-link.active, .nav-tabs .nav-link.active,
.nav-tabs .nav-item.show .nav-link { .nav-tabs .nav-item.show .nav-link {
background-color: transparent; background-color: transparent;
border-color: var(--border-color); border-color: var(--border-color);
} }
.nav-tabs .nav-link:hover, .nav-tabs .nav-link:hover,
.nav-tabs .nav-link:focus { .nav-tabs .nav-link:focus {
border-color: var(--border-color); border-color: var(--border-color);
} }
.form-control:focus { .form-control:focus {
color: var(--body-color); color: var(--body-color);
} }
} }
.tribute-container { .tribute-container {
border: 0; border: 0;
ul { ul {
margin-top: 0; margin-top: 0;
border-color: var(--border-color); border-color: var(--border-color);
} }
li { li {
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
border-top: 0; border-top: 0;
border-left: 0; border-left: 0;
border-right: 0; border-right: 0;
font-size: 13px; font-size: 13px;
&:not(:last-child) { &:not(:last-child) {
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
} }
&.highlight, &.highlight,
&:hover { &:hover {
color: var(--body-color); color: var(--body-color);
font-weight: bold; font-weight: bold;
background: rgba(44, 120, 191, 0.25); background: rgba(44, 120, 191, 0.25);
} }
} }
}
.ft-std {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
} }
.timeline-status-component { .timeline-status-component {
.username { .username {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
margin-bottom: -3px; margin-bottom: -3px;
word-break: break-word; word-break: break-word;
@media (min-width: 768px) { @media (min-width: 768px) {
font-size: 17px; font-size: 17px;
} }
} }
} }