mirror of
https://github.com/Retropex/bitfeed.git
synced 2025-05-13 03:30:47 +02:00
Mobile & caching fixes
This commit is contained in:
parent
a8a945e77e
commit
d386f01586
@ -31,7 +31,7 @@
|
|||||||
<meta name="msapplication-TileColor" content="#da532c">
|
<meta name="msapplication-TileColor" content="#da532c">
|
||||||
<meta name="theme-color" content="#ffffff">
|
<meta name="theme-color" content="#ffffff">
|
||||||
|
|
||||||
<link rel='stylesheet' href='/global.css'>
|
<link rel='stylesheet' href='/global.css?v=2.3.0'>
|
||||||
<link rel='stylesheet' href='/build/bundle.css'>
|
<link rel='stylesheet' href='/build/bundle.css'>
|
||||||
<script src="/env.js"></script>
|
<script src="/env.js"></script>
|
||||||
<script defer src="/build/bundle.js"></script>
|
<script defer src="/build/bundle.js"></script>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
import Icon from '../components/Icon.svelte'
|
import Icon from '../components/Icon.svelte'
|
||||||
import closeIcon from '../assets/icon/cil-x-circle.svg'
|
import closeIcon from '../assets/icon/cil-x-circle.svg'
|
||||||
import { shortBtcFormat, longBtcFormat, dateFormat, numberFormat } from '../utils/format.js'
|
import { shortBtcFormat, longBtcFormat, dateFormat, numberFormat } from '../utils/format.js'
|
||||||
import { exchangeRates, settings, blocksEnabled, latestBlockHeight, blockTransitionDirection, loading } from '../stores.js'
|
import { exchangeRates, settings, blocksEnabled, latestBlockHeight, blockTransitionDirection, loading, freezeResize, pageWidth, pageHeight } from '../stores.js'
|
||||||
import { formatCurrency } from '../utils/fx.js'
|
import { formatCurrency } from '../utils/fx.js'
|
||||||
import { searchBlockHeight } from '../utils/search.js'
|
import { searchBlockHeight } from '../utils/search.js'
|
||||||
|
|
||||||
@ -20,6 +20,18 @@
|
|||||||
let restoring = false
|
let restoring = false
|
||||||
let formattedBlockValue = ''
|
let formattedBlockValue = ''
|
||||||
|
|
||||||
|
let compactView
|
||||||
|
let landscape
|
||||||
|
let tinyView
|
||||||
|
$: {
|
||||||
|
if ($pageWidth && $pageHeight && !$freezeResize) {
|
||||||
|
const aspectRatio = ($pageWidth / $pageHeight)
|
||||||
|
landscape = aspectRatio >= 1
|
||||||
|
compactView = (aspectRatio < 1) && ($pageHeight < 760)
|
||||||
|
tinyView = (aspectRatio < 1) && ($pageHeight <= 400)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
if (block && block.value) {
|
if (block && block.value) {
|
||||||
const rate = $exchangeRates[$settings.currency]
|
const rate = $exchangeRates[$settings.currency]
|
||||||
@ -188,7 +200,7 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-aspect-ratio: 1/1) and (max-height: 760px) {
|
&.compact {
|
||||||
.compact {
|
.compact {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@ -196,14 +208,6 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media (aspect-ratio: 1/1) and (max-height: 760px) {
|
|
||||||
.compact {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.full-size {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.data-row {
|
.data-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -278,65 +282,61 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-aspect-ratio: 1/1) {
|
.block-info.landscape {
|
||||||
.block-info {
|
bottom: unset;
|
||||||
bottom: unset;
|
left: unset;
|
||||||
left: unset;
|
top: 0;
|
||||||
top: 0;
|
right: 100%;
|
||||||
right: 100%;
|
padding-right: .5rem;
|
||||||
padding-right: .5rem;
|
|
||||||
|
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
|
|
||||||
.data-row {
|
.data-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-end;
|
||||||
|
|
||||||
|
&.spacer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: flex-end;
|
|
||||||
|
|
||||||
&.spacer {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.data-field {
|
|
||||||
white-space: wrap;
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: 5px;
|
|
||||||
|
|
||||||
&.title-field {
|
|
||||||
margin-bottom: .5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.close-button {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.standalone.close-button {
|
.data-field {
|
||||||
display: block;
|
white-space: wrap;
|
||||||
position: absolute;
|
margin-left: 0;
|
||||||
bottom: 100%;
|
margin-right: 5px;
|
||||||
left: 100%;
|
|
||||||
margin: 5px;
|
&.title-field {
|
||||||
|
margin-bottom: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.close-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-aspect-ratio: 1/1) and (max-height: 400px) {
|
.standalone.landscape.close-button {
|
||||||
.standalone.close-button {
|
display: block;
|
||||||
top: 0;
|
position: absolute;
|
||||||
bottom: unset;
|
bottom: 100%;
|
||||||
margin-top: 0;
|
left: 100%;
|
||||||
}
|
margin: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.standalone.tinyscreen.close-button {
|
||||||
|
top: 0;
|
||||||
|
bottom: unset;
|
||||||
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
{#key transitionDirection}
|
{#key transitionDirection}
|
||||||
{#each ((block != null && visible && $blocksEnabled) ? [block] : []) as block (block.id)}
|
{#each ((block != null && visible && $blocksEnabled) ? [block] : []) as block (block.id)}
|
||||||
<div class="block-info-container" out:fly|local={flyOut} in:fly|local={flyIn}>
|
<div class="block-info-container" out:fly|local={flyOut} in:fly|local={flyIn}>
|
||||||
<div class="block-info">
|
<div class="block-info" class:compact={compactView} class:landscape={landscape}>
|
||||||
<!-- <span class="data-field">Hash: { block.id }</span> -->
|
<!-- <span class="data-field">Hash: { block.id }</span> -->
|
||||||
<div class="full-size">
|
<div class="full-size">
|
||||||
<div class="data-row">
|
<div class="data-row">
|
||||||
@ -363,7 +363,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="compact">
|
<div class="compact">
|
||||||
<div class="data-row">
|
<div class="data-row">
|
||||||
<span class="data-field title-field" title="{block.miner_sig}"><b>Latest Block: </b>{ numberFormat.format(block.height) }</span>
|
<span class="data-field title-field" title="{block.miner_sig}"><b>{#if block.height == $latestBlockHeight}Latest {/if}Block: </b>{ numberFormat.format(block.height) }</span>
|
||||||
<button class="data-field close-button" on:click={hideBlock}><Icon icon={closeIcon} color="var(--palette-x)" /></button>
|
<button class="data-field close-button" on:click={hideBlock}><Icon icon={closeIcon} color="var(--palette-x)" /></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="data-row">
|
<div class="data-row">
|
||||||
@ -371,7 +371,7 @@
|
|||||||
<span class="data-field">{ formattedBlockValue }</span>
|
<span class="data-field">{ formattedBlockValue }</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="data-row">
|
<div class="data-row">
|
||||||
<span class="data-field">{ formatCount(block.txnCount) } transactions</span>
|
<span class="data-field">{ formatCount(block.txnCount) } transaction{block.txnCount == 1 ? '' : 's'}</span>
|
||||||
{#if block.fees != null}
|
{#if block.fees != null}
|
||||||
<span class="data-field">{ formatFee(block.avgFeerate) } sats/vb</span>
|
<span class="data-field">{ formatFee(block.avgFeerate) } sats/vb</span>
|
||||||
{:else}
|
{:else}
|
||||||
@ -395,7 +395,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
{/if}
|
{/if}
|
||||||
<button class="close-button standalone" on:click={hideBlock}>
|
<button class="close-button standalone" class:landscape={landscape} class:tinyscreen={tinyView} on:click={hideBlock}>
|
||||||
<Icon icon={closeIcon} color="var(--palette-x)" />
|
<Icon icon={closeIcon} color="var(--palette-x)" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,7 +10,7 @@ import TxIcon from '../assets/icon/cil-arrow-circle-right.svg'
|
|||||||
import BlockIcon from '../assets/icon/grid-icon.svg'
|
import BlockIcon from '../assets/icon/grid-icon.svg'
|
||||||
import { fly } from 'svelte/transition'
|
import { fly } from 'svelte/transition'
|
||||||
import { matchQuery, searchTx, searchBlockHeight, searchBlockHash } from '../utils/search.js'
|
import { matchQuery, searchTx, searchBlockHeight, searchBlockHash } from '../utils/search.js'
|
||||||
import { selectedTx, detailTx, overlay, loading } from '../stores.js'
|
import { selectedTx, detailTx, overlay, loading, freezeResize } from '../stores.js'
|
||||||
|
|
||||||
const queryIcons = {
|
const queryIcons = {
|
||||||
txid: TxIcon,
|
txid: TxIcon,
|
||||||
@ -53,6 +53,8 @@ function handleSearchError (err) {
|
|||||||
async function searchSubmit (e) {
|
async function searchSubmit (e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
|
if (document.activeElement) document.activeElement.blur()
|
||||||
|
|
||||||
if (matchedQuery && matchedQuery.query !== 'address') {
|
if (matchedQuery && matchedQuery.query !== 'address') {
|
||||||
loading.increment()
|
loading.increment()
|
||||||
let searchErr
|
let searchErr
|
||||||
@ -87,6 +89,17 @@ async function searchSubmit (e) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let freezeTimeout
|
||||||
|
function focusIn(e) {
|
||||||
|
if (freezeTimeout) clearTimeout(freezeTimeout)
|
||||||
|
$freezeResize = true
|
||||||
|
}
|
||||||
|
async function focusOut(e) {
|
||||||
|
freezeTimeout = setTimeout(() => {
|
||||||
|
$freezeResize = false
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style type="text/scss">
|
<style type="text/scss">
|
||||||
@ -219,7 +232,7 @@ async function searchSubmit (e) {
|
|||||||
|
|
||||||
<div class="input-wrapper" transition:fly={{ y: -25 }}>
|
<div class="input-wrapper" transition:fly={{ y: -25 }}>
|
||||||
<form class="search-form" action="" on:submit={searchSubmit}>
|
<form class="search-form" action="" on:submit={searchSubmit}>
|
||||||
<input class="search-input" type="text" bind:value={query} placeholder="txid, block id or block height">
|
<input class="search-input" type="text" bind:value={query} placeholder="txid, block id or block height" on:focusin={focusIn} on:focusout={focusOut}>
|
||||||
<div class="clear-button" class:disabled={query == null || query === ''} on:click={clearInput} title="Clear">
|
<div class="clear-button" class:disabled={query == null || query === ''} on:click={clearInput} title="Clear">
|
||||||
<Icon icon={CrossIcon}/>
|
<Icon icon={CrossIcon}/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,7 +9,7 @@ import CrossIcon from '../assets/icon/cil-x.svg'
|
|||||||
import AddressIcon from '../assets/icon/cil-wallet.svg'
|
import AddressIcon from '../assets/icon/cil-wallet.svg'
|
||||||
import TxIcon from '../assets/icon/cil-arrow-circle-right.svg'
|
import TxIcon from '../assets/icon/cil-arrow-circle-right.svg'
|
||||||
import { matchQuery } from '../utils/search.js'
|
import { matchQuery } from '../utils/search.js'
|
||||||
import { highlight, newHighlightQuery, highlightingFull } from '../stores.js'
|
import { highlight, newHighlightQuery, highlightingFull, freezeResize } from '../stores.js'
|
||||||
import { hlToHex, highlightA, highlightB, highlightC, highlightD, highlightE } from '../utils/color.js'
|
import { hlToHex, highlightA, highlightB, highlightC, highlightD, highlightE } from '../utils/color.js'
|
||||||
|
|
||||||
const highlightColors = [highlightA, highlightB, highlightC, highlightD, highlightE]
|
const highlightColors = [highlightA, highlightB, highlightC, highlightD, highlightE]
|
||||||
@ -145,9 +145,21 @@ async function remove (index) {
|
|||||||
|
|
||||||
function searchSubmit (e) {
|
function searchSubmit (e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
if (document.activeElement) document.activeElement.blur()
|
||||||
add()
|
add()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let freezeTimeout
|
||||||
|
function focusIn(e) {
|
||||||
|
if (freezeTimeout) clearTimeout(freezeTimeout)
|
||||||
|
$freezeResize = true
|
||||||
|
}
|
||||||
|
async function focusOut(e) {
|
||||||
|
freezeTimeout = setTimeout(() => {
|
||||||
|
$freezeResize = false
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style type="text/scss">
|
<style type="text/scss">
|
||||||
@ -244,7 +256,7 @@ function searchSubmit (e) {
|
|||||||
<div class="input-wrapper" class:full={$highlightingFull} style="--input-color: {queryColorHex};">
|
<div class="input-wrapper" class:full={$highlightingFull} style="--input-color: {queryColorHex};">
|
||||||
{#if !$highlightingFull }
|
{#if !$highlightingFull }
|
||||||
<form class="search-form" action="" on:submit={searchSubmit}>
|
<form class="search-form" action="" on:submit={searchSubmit}>
|
||||||
<input class="search-input" type="text" bind:value={query} placeholder="Enter an address or txid...">
|
<input class="search-input" type="text" bind:value={query} placeholder="Enter an address or txid..." on:focusin={focusIn} on:focusOut={focusOut}>
|
||||||
<button type="submit" class="search-submit" />
|
<button type="submit" class="search-submit" />
|
||||||
</form>
|
</form>
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -20,7 +20,7 @@ import MempoolLegend from '../components/MempoolLegend.svelte'
|
|||||||
import ContactTab from '../components/ContactTab.svelte'
|
import ContactTab from '../components/ContactTab.svelte'
|
||||||
import SearchTab from '../components/SearchTab.svelte'
|
import SearchTab from '../components/SearchTab.svelte'
|
||||||
|
|
||||||
import { sidebarToggle, overlay, currentBlock, blockVisible, haveSupporters } from '../stores.js'
|
import { sidebarToggle, overlay, currentBlock, blockVisible, haveSupporters, freezeResize } from '../stores.js'
|
||||||
|
|
||||||
let searchTabComponent
|
let searchTabComponent
|
||||||
|
|
||||||
@ -58,12 +58,14 @@ function showBlock () {
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|
||||||
@media (max-width: 480px) and (max-height: 480px) {
|
@media (max-width: 480px) and (max-height: 480px) {
|
||||||
display: none;
|
&:not(.frozen) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="sidebar">
|
<div class="sidebar" class:frozen={$freezeResize}>
|
||||||
<!-- displayed in reverse order, to preserve proper z-index layering -->
|
<!-- displayed in reverse order, to preserve proper z-index layering -->
|
||||||
{#if blockHidden }
|
{#if blockHidden }
|
||||||
<SidebarTab on:click={() => showBlock()} tooltip="Show Latest Block">
|
<SidebarTab on:click={() => showBlock()} tooltip="Show Latest Block">
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
<script>
|
<script>
|
||||||
|
import { tick } from 'svelte'
|
||||||
import Toggle from './util/Toggle.svelte'
|
import Toggle from './util/Toggle.svelte'
|
||||||
import Pill from './util/Pill.svelte'
|
import Pill from './util/Pill.svelte'
|
||||||
import Select from 'svelte-select'
|
import Select from 'svelte-select'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
import { freezeResize } from '../stores.js'
|
||||||
const dispatch = createEventDispatcher()
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
export let value = false
|
export let value = false
|
||||||
@ -26,6 +28,18 @@ function filterSelectItems (label, filterText, option) {
|
|||||||
function onSelect (e) {
|
function onSelect (e) {
|
||||||
selectedOption = e.detail
|
selectedOption = e.detail
|
||||||
dispatch('input', selectedOption.value )
|
dispatch('input', selectedOption.value )
|
||||||
|
if (document.activeElement) document.activeElement.blur()
|
||||||
|
}
|
||||||
|
|
||||||
|
let freezeTimeout
|
||||||
|
function focusIn(e) {
|
||||||
|
if (freezeTimeout) clearTimeout(freezeTimeout)
|
||||||
|
$freezeResize = true
|
||||||
|
}
|
||||||
|
async function focusOut(e) {
|
||||||
|
freezeTimeout = setTimeout(() => {
|
||||||
|
$freezeResize = false
|
||||||
|
}, 500)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -73,7 +87,7 @@ function onSelect (e) {
|
|||||||
<span class="label">{ label }</span>
|
<span class="label">{ label }</span>
|
||||||
<Pill active={value} left={falseLabel} right={trueLabel} />
|
<Pill active={value} left={falseLabel} right={trueLabel} />
|
||||||
{:else if type === 'dropdown'}
|
{:else if type === 'dropdown'}
|
||||||
<div class="select">
|
<div class="select" on:focusin={focusIn} on:focusOut={focusOut}>
|
||||||
<Select items={ options } value={selectedOption} isSearchable={true} isClearable={false} itemFilter={filterSelectItems} placeholder={label} on:select={onSelect} showIndicator={true} />
|
<Select items={ options } value={selectedOption} isSearchable={true} isClearable={false} itemFilter={filterSelectItems} placeholder={label} on:select={onSelect} showIndicator={true} />
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
import fragShaderSrc from '../shaders/tx.frag'
|
import fragShaderSrc from '../shaders/tx.frag'
|
||||||
import TxSprite from '../models/TxSprite.js'
|
import TxSprite from '../models/TxSprite.js'
|
||||||
import { color, hcl } from 'd3-color'
|
import { color, hcl } from 'd3-color'
|
||||||
import { darkMode, frameRate, avgFrameRate, nativeAntialias, settings, devSettings } from '../stores.js'
|
import { darkMode, frameRate, avgFrameRate, nativeAntialias, settings, devSettings, freezeResize } from '../stores.js'
|
||||||
import config from '../config.js'
|
import config from '../config.js'
|
||||||
|
|
||||||
let canvas
|
let canvas
|
||||||
@ -32,6 +32,11 @@
|
|||||||
export let controller
|
export let controller
|
||||||
export let running = false
|
export let running = false
|
||||||
|
|
||||||
|
let sizeFrozen
|
||||||
|
freezeResize.subscribe(val => {
|
||||||
|
sizeFrozen = val
|
||||||
|
})
|
||||||
|
|
||||||
// Shader attributes
|
// Shader attributes
|
||||||
// each attribute (except index) contains [x: startValue, y: endValue, z: startTime, w: rate]
|
// each attribute (except index) contains [x: startValue, y: endValue, z: startTime, w: rate]
|
||||||
// shader interpolates between start and end values at the given rate, from the given time
|
// shader interpolates between start and end values at the given rate, from the given time
|
||||||
@ -72,9 +77,12 @@
|
|||||||
resizeCanvas()
|
resizeCanvas()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let resizeTimer
|
||||||
function resizeCanvas () {
|
function resizeCanvas () {
|
||||||
|
if (resizeTimer) clearTimeout(resizeTimer)
|
||||||
|
resizeTimer = null
|
||||||
// var rect = canvas.parentNode.getBoundingClientRect()
|
// var rect = canvas.parentNode.getBoundingClientRect()
|
||||||
if (canvas) {
|
if (canvas && !sizeFrozen) {
|
||||||
displayWidth = window.innerWidth
|
displayWidth = window.innerWidth
|
||||||
displayHeight = window.innerHeight
|
displayHeight = window.innerHeight
|
||||||
if (simulateAntialiasing) {
|
if (simulateAntialiasing) {
|
||||||
@ -86,7 +94,7 @@
|
|||||||
}
|
}
|
||||||
if (gl) gl.viewport(0, 0, canvas.width, canvas.height)
|
if (gl) gl.viewport(0, 0, canvas.width, canvas.height)
|
||||||
} else {
|
} else {
|
||||||
setTimeout(resizeCanvas, 500)
|
resizeTimer = setTimeout(resizeCanvas, 500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
import { settings, overlay, serverConnected, serverDelay, txCount, mempoolCount,
|
import { settings, overlay, serverConnected, serverDelay, txCount, mempoolCount,
|
||||||
mempoolScreenHeight, frameRate, avgFrameRate, blockVisible, tinyScreen,
|
mempoolScreenHeight, frameRate, avgFrameRate, blockVisible, tinyScreen,
|
||||||
compactScreen, currentBlock, latestBlockHeight, selectedTx, blockAreaSize,
|
compactScreen, currentBlock, latestBlockHeight, selectedTx, blockAreaSize,
|
||||||
devEvents, devSettings, pageWidth, pageHeight, loading } from '../stores.js'
|
devEvents, devSettings, pageWidth, pageHeight, loading, freezeResize } from '../stores.js'
|
||||||
import BlockInfo from '../components/BlockInfo.svelte'
|
import BlockInfo from '../components/BlockInfo.svelte'
|
||||||
import SearchBar from '../components/SearchBar.svelte'
|
import SearchBar from '../components/SearchBar.svelte'
|
||||||
import TxInfo from '../components/TxInfo.svelte'
|
import TxInfo from '../components/TxInfo.svelte'
|
||||||
@ -53,6 +53,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let canvasWidth = '100%'
|
||||||
|
let canvasHeight = '100%'
|
||||||
|
$: {
|
||||||
|
if ($freezeResize) {
|
||||||
|
canvasWidth = `${window.innerWidth}px`
|
||||||
|
canvasHeight = `${window.innerHeight}px`
|
||||||
|
} else {
|
||||||
|
canvasWidth = '100%'
|
||||||
|
canvasHeight = '100%'
|
||||||
|
resize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
txController = new TxController({ width, height })
|
txController = new TxController({ width, height })
|
||||||
|
|
||||||
@ -86,7 +99,7 @@
|
|||||||
function resize () {
|
function resize () {
|
||||||
$pageWidth = window.innerWidth
|
$pageWidth = window.innerWidth
|
||||||
$pageHeight = window.innerHeight
|
$pageHeight = window.innerHeight
|
||||||
if (width !== window.innerWidth - 20 || height !== window.innerHeight - 20) {
|
if ((width !== window.innerWidth - 20 || height !== window.innerHeight - 20) && !$freezeResize) {
|
||||||
// don't force resize unless the viewport has actually changed
|
// don't force resize unless the viewport has actually changed
|
||||||
width = window.innerWidth - 20
|
width = window.innerWidth - 20
|
||||||
height = window.innerHeight - 20
|
height = window.innerHeight - 20
|
||||||
@ -483,7 +496,7 @@
|
|||||||
<svelte:window on:resize={resize} on:load={resize} on:click={pointerLeave} />
|
<svelte:window on:resize={resize} on:load={resize} on:click={pointerLeave} />
|
||||||
<!-- <svelte:window on:resize={resize} on:click={pointerMove} /> -->
|
<!-- <svelte:window on:resize={resize} on:click={pointerMove} /> -->
|
||||||
|
|
||||||
<div class="tx-area" class:light-mode={!$settings.darkMode}>
|
<div class="tx-area" class:light-mode={!$settings.darkMode} style="width: {canvasWidth}; height: {canvasHeight}">
|
||||||
<div class="canvas-wrapper" on:pointerleave={pointerLeave} on:pointermove={pointerMove} on:click={onClick}>
|
<div class="canvas-wrapper" on:pointerleave={pointerLeave} on:pointermove={pointerMove} on:click={onClick}>
|
||||||
<TxRender controller={txController} />
|
<TxRender controller={txController} />
|
||||||
|
|
||||||
@ -539,13 +552,15 @@
|
|||||||
<SearchBar />
|
<SearchBar />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="alert-bar-wrapper">
|
{#if !$tinyScreen}
|
||||||
{#if config.messagesEnabled && $settings.showMessages && !$tinyScreen }
|
<div class="alert-bar-wrapper">
|
||||||
<Alerts />
|
{#if config.messagesEnabled && $settings.showMessages}
|
||||||
{:else}
|
<Alerts />
|
||||||
<div class="spacer"></div>
|
{:else}
|
||||||
{/if}
|
<div class="spacer"></div>
|
||||||
</div>
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
|
@ -152,13 +152,24 @@ export const highlightingFull = writable(false)
|
|||||||
|
|
||||||
export const pageWidth = writable(window.innerWidth)
|
export const pageWidth = writable(window.innerWidth)
|
||||||
export const pageHeight = writable(window.innerHeight)
|
export const pageHeight = writable(window.innerHeight)
|
||||||
|
export const freezeResize = writable(false)
|
||||||
|
|
||||||
export const tinyScreen = derived([pageWidth, pageHeight], ([$pageWidth, $pageHeight]) => {
|
let lastTinyScreen
|
||||||
const aspectRatio = $pageWidth / $pageHeight
|
export const tinyScreen = derived([pageWidth, pageHeight, freezeResize], ([$pageWidth, $pageHeight, $freezeResize]) => {
|
||||||
return (aspectRatio >= 1 && pageWidth < 480) || (aspectRatio <= 1 && $pageHeight < 480)
|
if ($freezeResize) return lastTinyScreen
|
||||||
|
else {
|
||||||
|
const aspectRatio = $pageWidth / $pageHeight
|
||||||
|
lastTinyScreen = (aspectRatio >= 1 && $pageWidth < 480) || (aspectRatio <= 1 && $pageHeight < 480)
|
||||||
|
return lastTinyScreen
|
||||||
|
}
|
||||||
})
|
})
|
||||||
export const compactScreen = derived([pageWidth, pageHeight], ([$pageWidth, $pageHeight]) => {
|
let lastCompactScreen
|
||||||
return ($pageWidth <= 640 && $pageHeight <= 550)
|
export const compactScreen = derived([pageWidth, pageHeight, freezeResize], ([$pageWidth, $pageHeight, $freezeResize]) => {
|
||||||
|
if ($freezeResize) return lastTinyScreen
|
||||||
|
else {
|
||||||
|
lastCompactScreen = ($pageWidth <= 640 && $pageHeight <= 550)
|
||||||
|
return lastCompactScreen
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const blocksEnabled = derived([settings], ([$settings]) => {
|
export const blocksEnabled = derived([settings], ([$settings]) => {
|
||||||
|
@ -34,7 +34,7 @@ defmodule BitcoinStream.Router do
|
|||||||
match "/api/block/:hash" do
|
match "/api/block/:hash" do
|
||||||
case get_block(hash) do
|
case get_block(hash) do
|
||||||
{:ok, block, true} ->
|
{:ok, block, true} ->
|
||||||
put_resp_header(conn, "cache-control", "public, max-age=120, immutable")
|
put_resp_header(conn, "cache-control", "public, max-age=1200, immutable")
|
||||||
|> send_resp(200, block)
|
|> send_resp(200, block)
|
||||||
|
|
||||||
{:ok, block, false} ->
|
{:ok, block, false} ->
|
||||||
|
Loading…
Reference in New Issue
Block a user