mirror of
https://git.sr.ht/~cadence/bibliogram
synced 2024-11-22 16:17:29 +00:00
Add IGTV
This commit is contained in:
parent
865e3b0778
commit
a023e09743
@ -12,7 +12,7 @@ const requestCache = new RequestCache(constants.caching.resource_cache_time)
|
|||||||
const userRequestCache = new UserRequestCache(constants.caching.resource_cache_time)
|
const userRequestCache = new UserRequestCache(constants.caching.resource_cache_time)
|
||||||
/** @type {import("./cache").TtlCache<import("./structures/TimelineEntry")>} */
|
/** @type {import("./cache").TtlCache<import("./structures/TimelineEntry")>} */
|
||||||
const timelineEntryCache = new TtlCache(constants.caching.resource_cache_time)
|
const timelineEntryCache = new TtlCache(constants.caching.resource_cache_time)
|
||||||
const history = new RequestHistory(["user", "timeline", "post", "reel"])
|
const history = new RequestHistory(["user", "timeline", "igtv", "post", "reel"])
|
||||||
|
|
||||||
const AssistantSwitcher = require("./structures/AssistantSwitcher")
|
const AssistantSwitcher = require("./structures/AssistantSwitcher")
|
||||||
const assistantSwitcher = new AssistantSwitcher()
|
const assistantSwitcher = new AssistantSwitcher()
|
||||||
@ -306,12 +306,12 @@ function fetchIGTVPage(userID, after) {
|
|||||||
if (res.status === 429) throw constants.symbols.RATE_LIMITED
|
if (res.status === 429) throw constants.symbols.RATE_LIMITED
|
||||||
}).then(g => g.json()).then(root => {
|
}).then(g => g.json()).then(root => {
|
||||||
/** @type {import("./types").PagedEdges<import("./types").TimelineEntryN2>} */
|
/** @type {import("./types").PagedEdges<import("./types").TimelineEntryN2>} */
|
||||||
const timeline = root.data.user.edge_owner_to_timeline_media
|
const timeline = root.data.user.edge_felix_video_timeline
|
||||||
history.report("timeline", true)
|
history.report("igtv", true)
|
||||||
return timeline
|
return timeline
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
if (error === constants.symbols.RATE_LIMITED) {
|
if (error === constants.symbols.RATE_LIMITED) {
|
||||||
history.report("timeline", false)
|
history.report("igtv", false)
|
||||||
}
|
}
|
||||||
throw error
|
throw error
|
||||||
})
|
})
|
||||||
@ -422,6 +422,7 @@ function fetchShortcodeData(shortcode) {
|
|||||||
|
|
||||||
module.exports.fetchUser = fetchUser
|
module.exports.fetchUser = fetchUser
|
||||||
module.exports.fetchTimelinePage = fetchTimelinePage
|
module.exports.fetchTimelinePage = fetchTimelinePage
|
||||||
|
module.exports.fetchIGTVPage = fetchIGTVPage
|
||||||
module.exports.getOrCreateShortcode = getOrCreateShortcode
|
module.exports.getOrCreateShortcode = getOrCreateShortcode
|
||||||
module.exports.fetchShortcodeData = fetchShortcodeData
|
module.exports.fetchShortcodeData = fetchShortcodeData
|
||||||
module.exports.userRequestCache = userRequestCache
|
module.exports.userRequestCache = userRequestCache
|
||||||
|
@ -12,8 +12,8 @@ class ReelUser extends BaseUser {
|
|||||||
this.posts = 0
|
this.posts = 0
|
||||||
this.following = data.edge_follow ? data.edge_follow.count : 0
|
this.following = data.edge_follow ? data.edge_follow.count : 0
|
||||||
this.followedBy = data.edge_followed_by ? data.edge_followed_by.count : 0
|
this.followedBy = data.edge_followed_by ? data.edge_followed_by.count : 0
|
||||||
/** @type {import("./Timeline")} */
|
this.timeline = new Timeline(this, "timeline")
|
||||||
this.timeline = new Timeline(this)
|
this.igtv = new Timeline(this, "igtv")
|
||||||
this.cachedAt = Date.now()
|
this.cachedAt = Date.now()
|
||||||
this.computeProxyProfilePic()
|
this.computeProxyProfilePic()
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,12 @@ function transformEdges(edges) {
|
|||||||
class Timeline {
|
class Timeline {
|
||||||
/**
|
/**
|
||||||
* @param {import("./User")|import("./ReelUser")} user
|
* @param {import("./User")|import("./ReelUser")} user
|
||||||
|
* @param {string} type
|
||||||
*/
|
*/
|
||||||
constructor(user) {
|
constructor(user, type) {
|
||||||
this.user = user
|
this.user = user
|
||||||
|
/** one of: "timeline", "igtv" */
|
||||||
|
this.type = type
|
||||||
/** @type {import("./TimelineEntry")[][]} */
|
/** @type {import("./TimelineEntry")[][]} */
|
||||||
this.pages = []
|
this.pages = []
|
||||||
if (this.user.data.edge_owner_to_timeline_media) {
|
if (this.user.data.edge_owner_to_timeline_media) {
|
||||||
@ -32,12 +35,17 @@ class Timeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasNextPage() {
|
hasNextPage() {
|
||||||
return this.page_info.has_next_page
|
return !this.page_info || this.page_info.has_next_page
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchNextPage() {
|
fetchNextPage() {
|
||||||
if (!this.hasNextPage()) return constants.symbols.NO_MORE_PAGES
|
if (!this.hasNextPage()) return constants.symbols.NO_MORE_PAGES
|
||||||
return collectors.fetchTimelinePage(this.user.data.id, this.page_info.end_cursor).then(page => {
|
const method =
|
||||||
|
this.type === "timeline" ? collectors.fetchTimelinePage
|
||||||
|
: this.type === "igtv" ? collectors.fetchIGTVPage
|
||||||
|
: null
|
||||||
|
const after = this.page_info ? this.page_info.end_cursor : ""
|
||||||
|
return method(this.user.data.id, after).then(page => {
|
||||||
this.addPage(page)
|
this.addPage(page)
|
||||||
return this.pages.slice(-1)[0]
|
return this.pages.slice(-1)[0]
|
||||||
})
|
})
|
||||||
|
@ -172,13 +172,23 @@ class TimelineEntry extends TimelineBaseMethods {
|
|||||||
config_height: found.config_height,
|
config_height: found.config_height,
|
||||||
src: proxyImage(found.src, found.config_width) // force resize to config rather than requested
|
src: proxyImage(found.src, found.config_width) // force resize to config rather than requested
|
||||||
}
|
}
|
||||||
|
} else if (this.data.thumbnail_src) {
|
||||||
|
return {
|
||||||
|
config_width: size, // probably?
|
||||||
|
config_height: size,
|
||||||
|
src: proxyImage(this.data.thumbnail_src, size) // force resize to requested
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getThumbnailSizes() {
|
getThumbnailSizes() {
|
||||||
return `(max-width: 820px) 200px, 260px` // from css :(
|
if (this.data.thumbnail_resources) {
|
||||||
|
return `(max-width: 820px) 200px, 260px` // from css :(
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchChildren() {
|
async fetchChildren() {
|
||||||
|
@ -13,7 +13,8 @@ class User extends BaseUser {
|
|||||||
this.following = data.edge_follow.count
|
this.following = data.edge_follow.count
|
||||||
this.followedBy = data.edge_followed_by.count
|
this.followedBy = data.edge_followed_by.count
|
||||||
this.posts = data.edge_owner_to_timeline_media.count
|
this.posts = data.edge_owner_to_timeline_media.count
|
||||||
this.timeline = new Timeline(this)
|
this.timeline = new Timeline(this, "timeline")
|
||||||
|
this.igtv = new Timeline(this, "igtv")
|
||||||
this.cachedAt = Date.now()
|
this.cachedAt = Date.now()
|
||||||
this.computeProxyProfilePic()
|
this.computeProxyProfilePic()
|
||||||
}
|
}
|
||||||
|
@ -65,22 +65,27 @@ module.exports = [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
route: `/u/(${constants.external.username_regex})`, methods: ["GET"], code: ({req, url, fill}) => {
|
route: `/u/(${constants.external.username_regex})(/channel)?`, methods: ["GET"], code: ({req, url, fill}) => {
|
||||||
if (fill[0] !== fill[0].toLowerCase()) { // some capital letters
|
const username = fill[0]
|
||||||
return Promise.resolve(redirect(`/u/${fill[0].toLowerCase()}`, 301))
|
const type = fill[1] ? "igtv" : "timeline"
|
||||||
|
|
||||||
|
if (username !== username.toLowerCase()) { // some capital letters
|
||||||
|
return Promise.resolve(redirect(`/u/${username.toLowerCase()}`, 301))
|
||||||
}
|
}
|
||||||
|
|
||||||
const settings = getSettings(req)
|
const settings = getSettings(req)
|
||||||
const params = url.searchParams
|
const params = url.searchParams
|
||||||
return fetchUser(fill[0]).then(async user => {
|
return fetchUser(username).then(async user => {
|
||||||
const page = +params.get("page")
|
const selectedTimeline = user[type]
|
||||||
if (typeof page === "number" && !isNaN(page) && page >= 1) {
|
let pageNumber = +params.get("page")
|
||||||
await user.timeline.fetchUpToPage(page - 1)
|
if (isNaN(pageNumber) || pageNumber < 1) pageNumber = 1
|
||||||
}
|
await selectedTimeline.fetchUpToPage(pageNumber - 1)
|
||||||
const followerCountsAvailable = !(user.constructor.name === "ReelUser" && user.following === 0 && user.followedBy === 0)
|
const followerCountsAvailable = !(user.constructor.name === "ReelUser" && user.following === 0 && user.followedBy === 0)
|
||||||
return render(200, "pug/user.pug", {
|
return render(200, "pug/user.pug", {
|
||||||
url,
|
url,
|
||||||
user,
|
user,
|
||||||
|
selectedTimeline,
|
||||||
|
type,
|
||||||
followerCountsAvailable,
|
followerCountsAvailable,
|
||||||
constants,
|
constants,
|
||||||
settings,
|
settings,
|
||||||
@ -100,12 +105,12 @@ module.exports = [
|
|||||||
statusCode: 503,
|
statusCode: 503,
|
||||||
contentType: "text/html",
|
contentType: "text/html",
|
||||||
headers: {
|
headers: {
|
||||||
"Retry-After": userRequestCache.getTtl("user/"+fill[0], 1000)
|
"Retry-After": userRequestCache.getTtl("user/"+username, 1000)
|
||||||
},
|
},
|
||||||
content: pugCache.get("pug/blocked.pug").web({
|
content: pugCache.get("pug/blocked.pug").web({
|
||||||
website_origin: constants.website_origin,
|
website_origin: constants.website_origin,
|
||||||
username: fill[0],
|
username,
|
||||||
expiresMinutes: userRequestCache.getTtl("user/"+fill[0], 1000*60),
|
expiresMinutes: userRequestCache.getTtl("user/"+username, 1000*60),
|
||||||
getStaticURL,
|
getStaticURL,
|
||||||
settings
|
settings
|
||||||
})
|
})
|
||||||
@ -120,13 +125,25 @@ module.exports = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
route: `/fragment/user/(${constants.external.username_regex})/(\\d+)`, methods: ["GET"], code: async ({req, url, fill}) => {
|
route: `/fragment/user/(${constants.external.username_regex})/(\\d+)`, methods: ["GET"], code: async ({req, url, fill}) => {
|
||||||
|
const username = fill[0]
|
||||||
|
let pageNumber = +fill[1]
|
||||||
|
if (isNaN(pageNumber) || pageNumber < 1) {
|
||||||
|
return {
|
||||||
|
statusCode: 400,
|
||||||
|
contentType: "text/html",
|
||||||
|
content: "Bad page number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let type = url.searchParams.get("type")
|
||||||
|
if (!["timeline", "igtv"].includes(type)) type = "timeline"
|
||||||
|
|
||||||
const settings = getSettings(req)
|
const settings = getSettings(req)
|
||||||
return fetchUser(fill[0]).then(async user => {
|
return fetchUser(username).then(async user => {
|
||||||
const pageNumber = +fill[1]
|
|
||||||
const pageIndex = pageNumber - 1
|
const pageIndex = pageNumber - 1
|
||||||
await user.timeline.fetchUpToPage(pageIndex)
|
const selectedTimeline = user[type]
|
||||||
if (user.timeline.pages[pageIndex]) {
|
await selectedTimeline.fetchUpToPage(pageIndex)
|
||||||
return render(200, "pug/fragments/timeline_page.pug", {page: user.timeline.pages[pageIndex], pageIndex, user, url, settings})
|
if (selectedTimeline.pages[pageIndex]) {
|
||||||
|
return render(200, "pug/fragments/timeline_page.pug", {page: selectedTimeline.pages[pageIndex], selectedTimeline, type, pageIndex, user, url, settings})
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
|
@ -75,8 +75,9 @@ class NextPage extends FreezeWidth {
|
|||||||
if (this.fetching) return
|
if (this.fetching) return
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
this.freeze("Loading...")
|
this.freeze("Loading...")
|
||||||
|
const type = this.element.getAttribute("data-type")
|
||||||
|
|
||||||
return fetch(`/fragment/user/${this.element.getAttribute("data-username")}/${this.nextPageNumber}`).then(res => res.text()).then(text => {
|
return fetch(`/fragment/user/${this.element.getAttribute("data-username")}/${this.nextPageNumber}?type=${type}`).then(res => res.text()).then(text => {
|
||||||
q("#next-page-container").remove()
|
q("#next-page-container").remove()
|
||||||
this.observer.disconnect()
|
this.observer.disconnect()
|
||||||
q("#timeline").insertAdjacentHTML("beforeend", text)
|
q("#timeline").insertAdjacentHTML("beforeend", text)
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
|
//- Needs user, selectedTimeline, url, type
|
||||||
|
|
||||||
include ../includes/timeline_page.pug
|
include ../includes/timeline_page.pug
|
||||||
include ../includes/next_page_button.pug
|
include ../includes/next_page_button.pug
|
||||||
|
|
||||||
+timeline_page(page, pageIndex)
|
+timeline_page(page, pageIndex)
|
||||||
|
|
||||||
+next_page_button(user, url)
|
+next_page_button(user, selectedTimeline, url, type)
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
mixin next_page_button(user, url)
|
mixin next_page_button(user, selectedTimeline, url, type)
|
||||||
if user.timeline.hasNextPage()
|
if selectedTimeline.hasNextPage()
|
||||||
div.next-page-container#next-page-container
|
div.next-page-container#next-page-container
|
||||||
-
|
-
|
||||||
const nu = new URL(url)
|
const nu = new URL(url)
|
||||||
nu.searchParams.set("page", user.timeline.pages.length+1)
|
nu.searchParams.set("page", selectedTimeline.pages.length+1)
|
||||||
a(href=`${nu.search}#page-${user.timeline.pages.length+1}` data-page=(user.timeline.pages.length+1) data-username=(user.data.username))#next-page.next-page Next page
|
a(href=`${nu.search}#page-${selectedTimeline.pages.length+1}` data-page=(selectedTimeline.pages.length+1) data-username=(user.data.username) data-type=type)#next-page.next-page Next page
|
||||||
else
|
else
|
||||||
div.page-number.no-more-pages
|
div.page-number.no-more-pages
|
||||||
span.number No more posts.
|
span.number No more posts.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//- Needs user, followerCountsAvailable, url, constants, settings
|
//- Needs user, selectedTimeline, type, followerCountsAvailable, url, constants, settings
|
||||||
|
|
||||||
include includes/timeline_page.pug
|
include includes/timeline_page.pug
|
||||||
include includes/next_page_button.pug
|
include includes/next_page_button.pug
|
||||||
@ -7,6 +7,9 @@ include includes/feed_link
|
|||||||
|
|
||||||
- const numberFormat = new Intl.NumberFormat().format
|
- const numberFormat = new Intl.NumberFormat().format
|
||||||
|
|
||||||
|
mixin selector-button(text, selectorType, urlSuffix)
|
||||||
|
a(href=(type !== selectorType && `/u/${user.data.username}${urlSuffix}`) class=(type === selectorType && "active")).selector= text
|
||||||
|
|
||||||
doctype html
|
doctype html
|
||||||
html
|
html
|
||||||
head
|
head
|
||||||
@ -77,17 +80,23 @@ html
|
|||||||
a(href="/") Home
|
a(href="/") Home
|
||||||
a(href=settingsReferrer) Settings
|
a(href=settingsReferrer) Settings
|
||||||
|
|
||||||
- const hasPosts = !user.data.is_private && user.timeline.pages.length && user.timeline.pages[0].length
|
- const hasPosts = !user.data.is_private && selectedTimeline.pages.length && selectedTimeline.pages[0].length
|
||||||
main(class=hasPosts ? "" : "no-posts")#timeline.timeline
|
.timeline-section
|
||||||
if hasPosts
|
.selector-container
|
||||||
each page, pageIndex in user.timeline.pages
|
+selector-button("Timeline", "timeline", "")
|
||||||
+timeline_page(page, pageIndex)
|
if user.data.has_channel !== false
|
||||||
+next_page_button(user, url)
|
+selector-button("IGTV", "igtv", "/channel")
|
||||||
else
|
|
||||||
div
|
main(class=hasPosts ? "" : "no-posts")#timeline.timeline
|
||||||
div.page-number
|
if hasPosts
|
||||||
span.number
|
each page, pageIndex in selectedTimeline.pages
|
||||||
if user.data.is_private
|
+timeline_page(page, pageIndex)
|
||||||
| Profile is private.
|
+next_page_button(user, selectedTimeline, url, type)
|
||||||
else
|
else
|
||||||
| No posts.
|
div
|
||||||
|
div.page-number
|
||||||
|
span.number
|
||||||
|
if user.data.is_private
|
||||||
|
| Profile is private.
|
||||||
|
else
|
||||||
|
| No posts.
|
||||||
|
@ -158,25 +158,41 @@ body
|
|||||||
@media screen and (max-width: $layout-a-max)
|
@media screen and (max-width: $layout-a-max)
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
.timeline
|
.timeline-section
|
||||||
--image-size: 260px
|
|
||||||
$image-size: var(--image-size)
|
|
||||||
|
|
||||||
@media screen and (max-width: $layout-a-max)
|
|
||||||
--image-size: 150px
|
|
||||||
flex: 1
|
|
||||||
|
|
||||||
@media screen and (max-width: $layout-c-max)
|
|
||||||
--image-size: calc(33vw - 10px)
|
|
||||||
|
|
||||||
background-color: map-get($theme, "background-primary")
|
background-color: map-get($theme, "background-primary")
|
||||||
padding: 15px 15px 40px
|
padding: 0px 15px 40px
|
||||||
|
|
||||||
&.no-posts
|
.selector-container
|
||||||
|
padding: 15px
|
||||||
display: flex
|
display: flex
|
||||||
flex-direction: column
|
|
||||||
justify-content: center
|
justify-content: center
|
||||||
|
|
||||||
|
.selector
|
||||||
|
background-color: map-get($theme, "background-primary")
|
||||||
|
color: map-get($theme, "foreground-primary")
|
||||||
|
text-decoration: none
|
||||||
|
padding: 10px 10px 13px
|
||||||
|
line-height: 1
|
||||||
|
font-size: 22px
|
||||||
|
border: 1px solid transparent
|
||||||
|
border-bottom: 1px solid map-get($theme, "foreground-timeline-page")
|
||||||
|
margin: 0px 10px
|
||||||
|
box-shadow: map-get($theme, "shadow-down-only")
|
||||||
|
border-radius: 5px
|
||||||
|
|
||||||
|
&:hover, &:focus
|
||||||
|
border: 1px solid map-get($theme, "foreground-timeline-page")
|
||||||
|
|
||||||
|
&.active
|
||||||
|
background-color: map-get($theme, "background-power-primary")
|
||||||
|
color: map-get($theme, "foreground-power-primary")
|
||||||
|
cursor: default
|
||||||
|
border: 1px solid map-get($theme, "foreground-timeline-page")
|
||||||
|
|
||||||
|
&:hover, &:focus, &.active
|
||||||
|
padding-bottom: 10px
|
||||||
|
border-bottom: 4px solid map-get($theme, "foreground-primary")
|
||||||
|
|
||||||
.page-number
|
.page-number
|
||||||
color: map-get($theme, "foreground-timeline-page")
|
color: map-get($theme, "foreground-timeline-page")
|
||||||
line-height: 1
|
line-height: 1
|
||||||
@ -201,71 +217,87 @@ body
|
|||||||
padding: 10px
|
padding: 10px
|
||||||
background-color: map-get($theme, "background-primary")
|
background-color: map-get($theme, "background-primary")
|
||||||
|
|
||||||
.next-page-container
|
.timeline
|
||||||
margin: 20px 0px
|
--image-size: 260px
|
||||||
display: flex
|
$image-size: var(--image-size)
|
||||||
justify-content: center
|
|
||||||
|
|
||||||
.next-page
|
@media screen and (max-width: $layout-a-max)
|
||||||
@include link-button
|
--image-size: 150px
|
||||||
font-size: 18px
|
flex: 1
|
||||||
text-align: center
|
|
||||||
|
|
||||||
.timeline-inner
|
|
||||||
display: flex
|
|
||||||
justify-content: center
|
|
||||||
flex-wrap: wrap
|
|
||||||
margin: 0 auto
|
|
||||||
|
|
||||||
&.three-columns
|
|
||||||
max-width: 810px
|
|
||||||
|
|
||||||
@media screen and (max-width: $layout-a-max)
|
|
||||||
max-width: 480px
|
|
||||||
|
|
||||||
&.four-columns
|
|
||||||
max-width: 1080px
|
|
||||||
|
|
||||||
&.six-columns
|
|
||||||
max-width: 1620px
|
|
||||||
|
|
||||||
@media screen and (max-width: $layout-c-max)
|
@media screen and (max-width: $layout-c-max)
|
||||||
display: grid
|
--image-size: calc(33vw - 10px)
|
||||||
grid-template-columns: repeat(3, 1fr)
|
|
||||||
|
&.no-posts
|
||||||
|
display: flex
|
||||||
|
flex-direction: column
|
||||||
justify-content: center
|
justify-content: center
|
||||||
justify-items: center
|
|
||||||
|
|
||||||
@mixin sized()
|
.next-page-container
|
||||||
width: $image-size
|
margin: 20px 0px
|
||||||
height: $image-size
|
display: flex
|
||||||
|
justify-content: center
|
||||||
|
|
||||||
.sized-link
|
.next-page
|
||||||
$margin: 5px
|
@include link-button
|
||||||
|
font-size: 18px
|
||||||
|
text-align: center
|
||||||
|
|
||||||
margin: $margin
|
.timeline-inner
|
||||||
color: map-get($theme, "foreground-thumbnail-alt")
|
display: flex
|
||||||
border: 0px map-get($theme, "edge-thumbnail-hover")
|
justify-content: center
|
||||||
background-color: map-get($theme, "background-timeline-loading")
|
flex-wrap: wrap
|
||||||
text-decoration: none
|
margin: 0 auto
|
||||||
overflow: hidden
|
|
||||||
@include sized
|
|
||||||
|
|
||||||
&:hover
|
&.three-columns
|
||||||
$border-width: 3px
|
max-width: 810px
|
||||||
margin: $margin - $border-width
|
|
||||||
border-width: $border-width
|
@media screen and (max-width: $layout-a-max)
|
||||||
|
max-width: 480px
|
||||||
|
|
||||||
|
&.four-columns
|
||||||
|
max-width: 1080px
|
||||||
|
|
||||||
|
&.six-columns
|
||||||
|
max-width: 1620px
|
||||||
|
|
||||||
@media screen and (max-width: $layout-c-max)
|
@media screen and (max-width: $layout-c-max)
|
||||||
$margin: 2px
|
display: grid
|
||||||
|
grid-template-columns: repeat(3, 1fr)
|
||||||
|
justify-content: center
|
||||||
|
justify-items: center
|
||||||
|
|
||||||
|
@mixin sized()
|
||||||
|
width: $image-size
|
||||||
|
height: $image-size
|
||||||
|
|
||||||
|
.sized-link
|
||||||
|
$margin: 5px
|
||||||
|
|
||||||
margin: $margin
|
margin: $margin
|
||||||
|
color: map-get($theme, "foreground-thumbnail-alt")
|
||||||
|
border: 0px map-get($theme, "edge-thumbnail-hover")
|
||||||
|
background-color: map-get($theme, "background-timeline-loading")
|
||||||
|
text-decoration: none
|
||||||
|
overflow: hidden
|
||||||
|
@include sized
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
$border-width: 2px
|
$border-width: 3px
|
||||||
margin: $margin - $border-width
|
margin: $margin - $border-width
|
||||||
border-width: $border-width
|
border-width: $border-width
|
||||||
|
|
||||||
.sized-image
|
@media screen and (max-width: $layout-c-max)
|
||||||
@include sized
|
$margin: 2px
|
||||||
|
margin: $margin
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
$border-width: 2px
|
||||||
|
margin: $margin - $border-width
|
||||||
|
border-width: $border-width
|
||||||
|
|
||||||
|
.sized-image
|
||||||
|
@include sized
|
||||||
|
|
||||||
.post-page
|
.post-page
|
||||||
background-color: map-get($theme, "background-post-distraction")
|
background-color: map-get($theme, "background-post-distraction")
|
||||||
|
@ -54,4 +54,5 @@ $theme: (
|
|||||||
"shadow-down": 0px -2px 4px 4px rgba(0, 0, 0, 0.4),
|
"shadow-down": 0px -2px 4px 4px rgba(0, 0, 0, 0.4),
|
||||||
"shadow-right": -2px 0px 4px 4px rgba(0, 0, 0, 0.4),
|
"shadow-right": -2px 0px 4px 4px rgba(0, 0, 0, 0.4),
|
||||||
"shadow-down-inset": 0px 6px 4px -4px rgba(0, 0, 0, 0.4) inset,
|
"shadow-down-inset": 0px 6px 4px -4px rgba(0, 0, 0, 0.4) inset,
|
||||||
|
"shadow-down-only": 0px 2px 4px 1px rgba(0, 0, 0, 0.3)
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user