one-time hints; builder touchups

This commit is contained in:
tim
2025-04-11 21:31:04 -04:00
parent 7973a1e8b7
commit 22f2e648a2
8 changed files with 84 additions and 43 deletions

View File

@@ -8,6 +8,7 @@ import {tvCustomThemes} from "../../theme.js";
export let widget = null
export let chart = null
export let crosshairPoint = null
export let defaultShapeHandler = null // if set, then TV events that dont have a registered shape handler get passed directly to this function
let symbolChangedCbs = [] // callbacks for TV's chart.onSymbolChanged()
@@ -268,6 +269,7 @@ export function drawShape(shapeType, ...callbacks) {
drawingTool = null
previousDrawingTool = widget.selectedLineTool()
co.drawing = true
co.drew = false
widget.selectLineTool(shapeType.code)
invokeCallbacks(callbacks, 'onDraw')
}
@@ -462,9 +464,11 @@ function doHandleDrawingEvent(id, event) {
const props = shape.getProperties()
if (id in shapeCallbacks)
invokeCallbacks(shapeCallbacks[id], 'onProps', id, shape, props)
else
// otherwise it's an event on a shape we don't "own"
else {
// otherwise it's an event on a shape we don't "own" that could be being drawn
co.drew = true
console.log('warning: ignoring setProperties on TV shape', id, props)
}
} else if (event === 'move') {
if (id in shapeCallbacks) {
invokeCallbacks(shapeCallbacks[id], 'onMove', id, shape)

View File

@@ -1,5 +1,5 @@
<template>
<v-tooltip v-model="show" :close-on-content-click="true"/>
<v-tooltip v-model="show" :close-on-content-click="true" :close-on-back="false" :close-delay="null"/>
</template>
<script setup>
@@ -8,25 +8,26 @@ import {usePrefStore} from "@/store/store.js";
const prefs = usePrefStore()
const modelValue = defineModel()
const hasBeenShown = ref(false)
const props = defineProps({
key: {type: String, required: true},
after: {type: String, default: null},
name: {type: String, required: true},
when: {type: Boolean, default: true}, // optional conditional for when to show
after: {type: String, default: null}, // set to the name of another hint that must happen before this hint, to chain hints into a tutorial.
})
const forceClose = ref(false)
const show = computed({
get() {
const result = !prefs.hints[props.key] && modelValue.value && (props.after === null || prefs.hints[props.after])
&& !props.finished
const shownBefore = prefs.hints[props.name];
const whenOk = props.when;
const afterOk = props.after === null || prefs.hints[props.after];
const result = !forceClose.value && !shownBefore && whenOk && afterOk
// console.log(`show ${props.name}? ${result} <=`, !forceClose.value, whenOk, afterOk, prefs.hints)
if (result)
hasBeenShown.value = true
else if (hasBeenShown.value)
prefs.hints[props.key] = true
prefs.hints[props.name] = true
return result
},
set(v) { if(!v) prefs.hints[props.key] = true}
set(v) { if(!v) forceClose.value=true; }
})
</script>

View File

@@ -1,9 +1,8 @@
<template>
<div ref="element" class="chart"/>
<div id="tv-widget" ref="element" class="chart"/>
</template>
<script setup>
// import "/public/datafeeds/udf/dist/bundle.js"
import {onMounted, ref} from "vue";
import {initWidget} from "@/charts/chart.js";
@@ -12,18 +11,8 @@ const element = ref()
onMounted(() => {
const el = element.value;
initWidget(el)
initShapes()
})
function initShapes() {
// const c = widget.chart()
// for( const s of ss.shapes ) {
// const type = s.type.toLowerCase().replace(' ','_')
// console.log('create type', type)
// c.createMultipointShape(s.points, {shape:type})
// }
}
</script>
<style scoped lang="scss">

View File

@@ -11,28 +11,28 @@
<v-tooltip text="Up to 1000 equal parts spread across time" location="top">
<template v-slot:activator="{ props }">
<span v-bind="props">
<v-btn :class="order.buy?'green':'red'" variant="text" prepend-icon="mdi-clock-outline" @click="build(order,'DCABuilder')">DCA</v-btn>
<v-btn id="DCA-button" :class="order.buy?'green':'red'" variant="text" prepend-icon="mdi-clock-outline" @click="build(order,'DCABuilder')">DCA</v-btn>
</span>
</template>
</v-tooltip>
<v-tooltip text="Trade a price level" location="top">
<template v-slot:activator="{ props }">
<span v-bind="props">
<v-btn :class="order.buy?'green':'red'" variant="text" prepend-icon="mdi-ray-vertex" @click="build(order,'LimitBuilder')">Limit</v-btn>
<v-btn id="LimitBuilder-button" :class="order.buy?'green':'red'" variant="text" prepend-icon="mdi-ray-vertex" @click="build(order,'LimitBuilder')">Limit</v-btn>
</span>
</template>
</v-tooltip>
<v-tooltip text="Trade trends and channels" location="top">
<template v-slot:activator="{ props }">
<span v-bind="props">
<v-btn :class="order.buy?'green':'red'" variant="text" prepend-icon="mdi-vector-line" @click="build(order,'DiagonalBuilder')">Diagonal</v-btn>
<v-btn id="Diagonal-button" :class="order.buy?'green':'red'" variant="text" prepend-icon="mdi-vector-line" @click="build(order,'DiagonalBuilder')">Diagonal</v-btn>
</span>
</template>
</v-tooltip>
<v-tooltip text="Up to 10 weighted parts spaced out in time" location="top">
<template v-slot:activator="{ props }">
<span v-bind="props">
<v-btn :class="order.buy?'green':'red'" variant="text" prepend-icon="mdi-reorder-vertical" @click="build(order,'DateBuilder')">Dates</v-btn>
<v-btn id="Dates-button" :class="order.buy?'green':'red'" variant="text" prepend-icon="mdi-reorder-vertical" @click="build(order,'DateBuilder')">Dates</v-btn>
</span>
</template>
</v-tooltip>
@@ -44,6 +44,13 @@
</template>
</v-tooltip>
<!-- mdi-ray-start-end mdi-vector-polyline -->
<!-- after="newbie"-->
<span>{{builders.length}}</span>
<one-time-hint name="choose-builder" :activator="hintData.activator"
:text="hintData.text" location="top"
:when="!builtAny"/>
</div>
</div>
</div>
@@ -55,7 +62,7 @@
import BuilderFactory from "@/components/chart/BuilderFactory.vue";
import {builderFuncs, newBuilder, orderFuncs, useChartOrderStore} from "@/orderbuild.js";
import {useStore} from "@/store/store.js";
import {computed, onUnmounted, onUpdated, watchEffect} from "vue";
import {computed, onUnmounted, onUpdated, ref, watchEffect} from "vue";
import {toPrecision} from "@/misc.js";
import {useTheme} from "vuetify";
import RowBar from "@/components/chart/RowBar.vue";
@@ -63,6 +70,7 @@ import Color from "color";
import {newOrder} from "@/blockchain/orderlib.js";
import OrderAmount from "@/components/chart/OrderAmount.vue";
import {track} from "@/track.js";
import OneTimeHint from "@/components/OneTimeHint.vue";
const props = defineProps(['order'])
const s = useStore()
@@ -75,9 +83,12 @@ const tokenIn = computed(()=>props.order.buy ? co.quoteToken : co.baseToken)
const tokenOut = computed(()=>props.order.buy ? co.baseToken : co.quoteToken)
const builtAny = ref(false)
console.log('order', props.order)
function build(order, component, options={}) {
track('build', {builder:component})
builtAny.value = true
order.builders.push(newBuilder(component, options))
}
@@ -187,6 +198,19 @@ const color = computed(()=>theme.value.colors["on-background"])
// const lightColorStyle = computed(() => { return {'background-color': lightColor.value} })
// const faintColorStyle = computed(() => { return {'background-color': faintColor.value} })
// Tutorial Hint
let tutorial = 'limit'
const _hintData = {
'limit': {
activator: '#LimitBuilder-button',
text: '↓ Try a Limit Ladder ↓'
},
}
const hintData = computed(()=>_hintData[tutorial] || _hintData['limit'])
</script>
<style scoped lang="scss">

View File

@@ -89,6 +89,7 @@
</tr>
</tbody>
</table>
<one-time-hint name="click-chart" activator="#tv-widget" location="center" :when="builder.lineA===null && !co.drew" text="Click the chart!"/>
</rung-builder>
</template>
@@ -102,6 +103,7 @@ import {allocationText, DLine} from "@/charts/shape.js";
import {vectorEquals, vectorInterpolate} from "@/vector.js";
import AbsoluteTimeEntry from "@/components/AbsoluteTimeEntry.vue";
import {useStore} from "@/store/store.js";
import OneTimeHint from "@/components/OneTimeHint.vue";
const s = useStore()
const co = useChartOrderStore()

View File

@@ -33,10 +33,11 @@
style="flex: 6em"
/>
</td>
<td class="weight">{{ weights.length ? allocationTexts[lowerIndex] : '' }}</td>
<td class="weight">{{ weights.length > 1 ? allocationTexts[lowerIndex] : '' }}</td>
</tr>
</tbody>
</table>
<one-time-hint name="click-chart" activator="#tv-widget" location="center" :when="priceA===null" text="Click the chart!"/>
</rung-builder>
</template>
@@ -48,6 +49,7 @@ import {MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js";
import RungBuilder from "@/components/chart/RungBuilder.vue";
import {computed, ref} from "vue";
import {allocationText, HLine} from "@/charts/shape.js";
import OneTimeHint from "@/components/OneTimeHint.vue";
const s = useStore()
const os = useOrderStore()

View File

@@ -17,15 +17,27 @@
min="1" :max="MAX_RUNGS"
:disabled="rungsDisabled"
style="width: 6.6em; max-height: 2.5em; height: 2.5em"
id="rungs"
/>
<one-time-hint name="rungs" activator="#rungs" after="choose-builder"
text="↓ Try increasing rungs!" location="top"
:when="rungs===1&&endpoints[0]!==null"/>
<v-tooltip v-if="builder.breakout!==undefined"
:text="order.buy?'Breakout orders buy above the breakout line':'Breakdown orders sell below the breakdown line'">
<template #activator="{ props }">
<div v-bind="props">
<v-switch v-model="breakout" :label="order.buy?'Breakout':'Breakdown'"
persistent-hint :color="switchColor" :base-color="switchColor" hide-details direction="vertical"
density="compact"
/>
<div class="mx-auto"><span style="font-size: .7em; vertical-align: top"
density="compact"/>
<div class="mx-auto">
<span style="font-size: .7em; vertical-align: top"
:style="builder.breakout?{color:new Color(color).lighten(0.5).string()}:null">
{{description}}
</span></div>
{{ description }}
</span>
</div>
</div>
</template>
</v-tooltip>
</div>
<slot/>
@@ -36,8 +48,13 @@
</div>
<div v-if="rungs>1" class="mx-2 d-flex justify-start">
<div class="d-flex align-center mt-2">
<div id="balance-slider">
<v-slider v-if="rungs>1" :direction="orientation?'vertical':'horizontal'" min="-100" max="100" v-model="balance100"
class="no-slider-bg ml-2 mr-4" hide-details/>
</div>
<one-time-hint name="balance-slider" activator="#balance-slider" after="rungs"
text="↓ Slide the amount balance ↓" location="top"
:when="balance100===0"/>
<v-text-field type="number" v-model="balance100" min="-100" max="100"
density="compact" hide-details variant="outlined" label="Balance" step="5"
class="balance">
@@ -70,6 +87,7 @@ import {
vectorSub
} from "@/vector.js";
import {logicalXOR} from "@/common.js";
import OneTimeHint from "@/components/OneTimeHint.vue";
const co = useChartOrderStore()
const endpoints = defineModel('modelValue') // 2-item list of points/values

View File

@@ -68,6 +68,7 @@ export const useChartOrderStore = defineStore('chart_orders', () => {
const meanRange = ref(1)
const drawing = ref(false)
const drew = ref(true) // true if at least one of the points has been drawn already
function newOrder() {
const order = newDefaultOrder()
@@ -97,7 +98,7 @@ export const useChartOrderStore = defineStore('chart_orders', () => {
return {
chartReady, selectedSymbol, intervalSecs, baseToken, quoteToken, price,
orders, drawing, newOrder, removeOrder, resetOrders, meanRange,
orders, drawing, drew, newOrder, removeOrder, resetOrders, meanRange,
showPoolSelection,
}
})