Merge pull request 'Add hints for clips, antennas, lists, and timelines' (#10226) from Freeplay/calckey:hints into develop

Reviewed-on: https://codeberg.org/calckey/calckey/pulls/10226
This commit is contained in:
Kainoa Kanter 2023-05-29 19:16:56 +00:00
commit 78c493f82c
11 changed files with 211 additions and 79 deletions

View File

@ -83,6 +83,7 @@ exportRequested: "You've requested an export. This may take a while. It will be
\ to your Drive once completed." \ to your Drive once completed."
importRequested: "You've requested an import. This may take a while." importRequested: "You've requested an import. This may take a while."
lists: "Lists" lists: "Lists"
listsDesc: "Lists let you create timelines with specified users. They can be accessed from the timelines page."
noLists: "You don't have any lists" noLists: "You don't have any lists"
note: "Post" note: "Post"
notes: "Posts" notes: "Posts"
@ -405,6 +406,7 @@ avoidMultiCaptchaConfirm: "Using multiple Captcha systems may cause interference
\ them. Would you like to disable the other Captcha systems currently active? If\ \ them. Would you like to disable the other Captcha systems currently active? If\
\ you would like them to stay enabled, press cancel." \ you would like them to stay enabled, press cancel."
antennas: "Antennas" antennas: "Antennas"
antennasDesc: "Antennas display new posts matching the criteria you set!\n They can be accessed from the timelines page."
manageAntennas: "Manage Antennas" manageAntennas: "Manage Antennas"
name: "Name" name: "Name"
antennaSource: "Antenna source" antennaSource: "Antenna source"
@ -686,6 +688,7 @@ logs: "Logs"
delayed: "Delayed" delayed: "Delayed"
database: "Database" database: "Database"
channel: "Channels" channel: "Channels"
channelFederationWarn: "Channels do not yet federate to other servers"
create: "Create" create: "Create"
notificationSetting: "Notification settings" notificationSetting: "Notification settings"
notificationSettingDesc: "Select the types of notification to display." notificationSettingDesc: "Select the types of notification to display."
@ -771,6 +774,7 @@ pageLikedCount: "Number of received Page likes"
contact: "Contact" contact: "Contact"
useSystemFont: "Use the system's default font" useSystemFont: "Use the system's default font"
clips: "Clips" clips: "Clips"
clipsDesc: "Clips are like share-able categorized bookmarks. You can create clips from the menu of individual posts."
experimentalFeatures: "Experimental features" experimentalFeatures: "Experimental features"
developer: "Developer" developer: "Developer"
makeExplorable: "Make account visible in \"Explore\"" makeExplorable: "Make account visible in \"Explore\""

View File

@ -1,21 +1,39 @@
<template> <template>
<div class="fpezltsf" :class="{ warn }"> <div v-if="visible" class="info" :class="{ warn, card }">
<i v-if="warn" class="ph-warning ph-bold ph-lg"></i> <i v-if="warn" class="ph-warning ph-bold ph-lg"></i>
<i v-else class="ph-info ph-bold ph-lg"></i> <i v-else class="ph-bold ph-lg" :class="icon ? `ph-${icon}` : 'ph-info'"></i>
<slot></slot> <slot></slot>
<button v-if="closeable" class="_button close" @click.stop="close">
<i class="ph-x ph-bold ph-lg"></i>
</button>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import {} from "vue"; import { ref } from "vue";
const visible = ref(true);
defineProps<{ defineProps<{
icon?: string;
warn?: boolean; warn?: boolean;
card?: boolean;
closeable?: boolean;
}>(); }>();
const emit = defineEmits<{
(ev: "close"): void;
}>();
function close() {
visible.value = false;
emit("close");
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.fpezltsf { .info {
padding: 16px; padding: 16px;
font-size: 90%; font-size: 90%;
background: var(--infoBg); background: var(--infoBg);
@ -27,8 +45,34 @@ defineProps<{
color: var(--infoWarnFg); color: var(--infoWarnFg);
} }
&.card {
background: var(--panel);
color: var(--fg);
padding: 48px;
font-size: 1em;
text-align: center;
> i {
display: block;
font-size: 4em;
margin: 0;
}
> :deep(*) {
margin-inline: auto;
}
> :deep(:not(:last-child)) {
margin-bottom: 20px;
}
> :deep(p) {
max-width: 30em;
}
}
> i { > i {
margin-right: 4px; margin-right: 4px;
} }
> .close {
margin-left: auto;
float: right;
}
} }
</style> </style>

View File

@ -17,7 +17,7 @@
</slot> </slot>
</div> </div>
<div v-else ref="rootEl"> <div v-else ref="rootEl" class="list">
<div <div
v-show="pagination.reversed && more" v-show="pagination.reversed && more"
key="_more_" key="_more_"
@ -487,4 +487,11 @@ defineExpose({
margin-right: auto; margin-right: auto;
} }
} }
.list > :deep(._button) {
margin-inline: auto;
margin-bottom: 16px;
&:last-of-type:not(:first-child) {
margin-top: 16px;
}
}
</style> </style>

View File

@ -1,4 +1,11 @@
<template> <template>
<MkInfo v-if="tlHint && !tlHintClosed" :closeable="true" class="_gap" @close="closeHint">
<I18n
:src="tlHint"
>
<template #icon></template>
</I18n>
</MkInfo>
<XNotes <XNotes
ref="tlComponent" ref="tlComponent"
:no-gap="!$store.state.showGapBetweenNotesInTimeline" :no-gap="!$store.state.showGapBetweenNotesInTimeline"
@ -10,10 +17,13 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, provide, onUnmounted } from "vue"; import { ref, computed, provide, onUnmounted } from "vue";
import XNotes from "@/components/MkNotes.vue"; import XNotes from "@/components/MkNotes.vue";
import MkInfo from "@/components/MkInfo.vue";
import * as os from "@/os"; import * as os from "@/os";
import { stream } from "@/stream"; import { stream } from "@/stream";
import * as sound from "@/scripts/sound"; import * as sound from "@/scripts/sound";
import { $i } from "@/account"; import { $i } from "@/account";
import { i18n } from "@/i18n";
import { defaultStore } from "@/store";
const props = defineProps<{ const props = defineProps<{
src: string; src: string;
@ -64,6 +74,9 @@ let query;
let connection; let connection;
let connection2; let connection2;
let tlHint;
let tlHintClosed;
if (props.src === "antenna") { if (props.src === "antenna") {
endpoint = "antennas/notes"; endpoint = "antennas/notes";
query = { query = {
@ -81,22 +94,37 @@ if (props.src === "antenna") {
connection2 = stream.useChannel("main"); connection2 = stream.useChannel("main");
connection2.on("follow", onChangeFollowing); connection2.on("follow", onChangeFollowing);
connection2.on("unfollow", onChangeFollowing); connection2.on("unfollow", onChangeFollowing);
tlHint = i18n.ts._tutorial.step5_3;
tlHintClosed = defaultStore.state.tlHomeHintClosed;
} else if (props.src === "local") { } else if (props.src === "local") {
endpoint = "notes/local-timeline"; endpoint = "notes/local-timeline";
connection = stream.useChannel("localTimeline"); connection = stream.useChannel("localTimeline");
connection.on("note", prepend); connection.on("note", prepend);
tlHint = i18n.ts._tutorial.step5_4;
tlHintClosed = defaultStore.state.tlLocalHintClosed;
} else if (props.src === "recommended") { } else if (props.src === "recommended") {
endpoint = "notes/recommended-timeline"; endpoint = "notes/recommended-timeline";
connection = stream.useChannel("recommendedTimeline"); connection = stream.useChannel("recommendedTimeline");
connection.on("note", prepend); connection.on("note", prepend);
tlHint = i18n.ts._tutorial.step5_6;
tlHintClosed = defaultStore.state.tlRecommendedHintClosed;
} else if (props.src === "social") { } else if (props.src === "social") {
endpoint = "notes/hybrid-timeline"; endpoint = "notes/hybrid-timeline";
connection = stream.useChannel("hybridTimeline"); connection = stream.useChannel("hybridTimeline");
connection.on("note", prepend); connection.on("note", prepend);
tlHint = i18n.ts._tutorial.step5_5;
tlHintClosed = defaultStore.state.tlSocialHintClosed;
} else if (props.src === "global") { } else if (props.src === "global") {
endpoint = "notes/global-timeline"; endpoint = "notes/global-timeline";
connection = stream.useChannel("globalTimeline"); connection = stream.useChannel("globalTimeline");
connection.on("note", prepend); connection.on("note", prepend);
tlHint = i18n.ts._tutorial.step5_7;
tlHintClosed = defaultStore.state.tlGlobalHintClosed;
} else if (props.src === "mentions") { } else if (props.src === "mentions") {
endpoint = "notes/mentions"; endpoint = "notes/mentions";
connection = stream.useChannel("main"); connection = stream.useChannel("main");
@ -135,6 +163,26 @@ if (props.src === "antenna") {
connection.on("note", prepend); connection.on("note", prepend);
} }
function closeHint() {
switch (props.src) {
case 'home':
defaultStore.set("tlHomeHintClosed", true);
break;
case 'local':
defaultStore.set("tlLocalHintClosed", true);
break;
case 'recommended':
defaultStore.set("tlRecommendedHintClosed", true);
break;
case 'social':
defaultStore.set("tlSocialHintClosed", true);
break;
case 'global':
defaultStore.set("tlGlobalHintClosed", true);
break;
}
}
const pagination = { const pagination = {
endpoint: endpoint, endpoint: endpoint,
limit: 10, limit: 10,

View File

@ -7,6 +7,7 @@
:tabs="headerTabs" :tabs="headerTabs"
/></template> /></template>
<MkSpacer :content-max="700"> <MkSpacer :content-max="700">
<MkInfo class="_gap" :warn="true">{{ i18n.ts.channelFederationWarn }}</MkInfo>
<swiper <swiper
:round-lengths="true" :round-lengths="true"
:touch-angle="25" :touch-angle="25"
@ -119,6 +120,7 @@ import MkInput from "@/components/form/input.vue";
import MkRadios from "@/components/form/radios.vue"; import MkRadios from "@/components/form/radios.vue";
import MkButton from "@/components/MkButton.vue"; import MkButton from "@/components/MkButton.vue";
import MkFolder from "@/components/MkFolder.vue"; import MkFolder from "@/components/MkFolder.vue";
import MkInfo from "@/components/MkInfo.vue";
import { useRouter } from "@/router"; import { useRouter } from "@/router";
import { definePageMetadata } from "@/scripts/page-metadata"; import { definePageMetadata } from "@/scripts/page-metadata";
import { deviceKind } from "@/scripts/device-kind"; import { deviceKind } from "@/scripts/device-kind";

View File

@ -1,7 +1,9 @@
<template> <template>
<div class="geegznzt"> <MkSpacer :content-max="700">
<XAntenna :antenna="draft" @created="onAntennaCreated" /> <div class="geegznzt">
</div> <XAntenna :antenna="draft" @created="onAntennaCreated" />
</div>
</MkSpacer>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -8,43 +8,50 @@
/></template> /></template>
<MkSpacer :content-max="700"> <MkSpacer :content-max="700">
<div class="ieepwinx"> <div class="ieepwinx">
<MkButton <MkInfo
:link="true" class="_gap"
to="/my/antennas/create" :icon="'flying-saucer'"
primary :card="true"
class="add"
><i class="ph-plus ph-bold ph-lg"></i>
{{ i18n.ts.add }}</MkButton
> >
<p>{{ i18n.ts.antennasDesc }}</p>
<MkButton
:link="true"
to="/my/antennas/create"
primary
class="add"
><i class="ph-plus ph-bold ph-lg"></i>
{{ i18n.ts.add }}</MkButton
>
</MkInfo>
<div class=""> <div class="">
<MkPagination <MkPagination
v-slot="{ items }"
ref="list" ref="list"
:pagination="pagination" :pagination="pagination"
> >
<div v-for="antenna in items" :key="antenna.id"> <template #default="{ items }">
<MkA <div v-for="antenna in items" :key="antenna.id">
class="uopelskx" <MkA
:link="true" class="uopelskx"
:to="`/timeline/antenna/${antenna.id}`" :link="true"
> :to="`/timeline/antenna/${antenna.id}`"
<i class="ph-flying-saucer ph-bold ph-lg"></i >
><i <i class="ph-flying-saucer ph-bold ph-lg"></i
:class="`${ ><i
antenna.hasUnreadNote :class="`${
? 'ph-circle ph-fill' antenna.hasUnreadNote
: 'ph-check' ? 'ph-circle ph-fill'
} ph-xs notify-icon`" : 'ph-check'
></i> } ph-xs notify-icon`"
</MkA> ></i>
<MkA </MkA>
class="ljoevbzj" <MkA
:to="`/my/antennas/${antenna.id}`" class="ljoevbzj"
> :to="`/my/antennas/${antenna.id}`"
<div class="name">{{ antenna.name }}</div> >
</MkA> <div class="name">{{ antenna.name }}</div>
</div> </MkA>
</div>
</template>
</MkPagination> </MkPagination>
</div> </div>
</div> </div>
@ -56,6 +63,7 @@
import { onActivated, onDeactivated, ref } from "vue"; import { onActivated, onDeactivated, ref } from "vue";
import MkPagination from "@/components/MkPagination.vue"; import MkPagination from "@/components/MkPagination.vue";
import MkButton from "@/components/MkButton.vue"; import MkButton from "@/components/MkButton.vue";
import MkInfo from "@/components/MkInfo.vue";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
import { definePageMetadata } from "@/scripts/page-metadata"; import { definePageMetadata } from "@/scripts/page-metadata";
@ -101,10 +109,6 @@ definePageMetadata({
<style lang="scss" scoped> <style lang="scss" scoped>
.ieepwinx { .ieepwinx {
> .add {
margin: 0 auto 16px auto;
}
.uopelskx { .uopelskx {
float: left; float: left;
min-width: 25px; min-width: 25px;

View File

@ -8,28 +8,32 @@
/></template> /></template>
<MkSpacer :content-max="700"> <MkSpacer :content-max="700">
<div class="qtcaoidl"> <div class="qtcaoidl">
<MkButton primary class="add" @click="create"
><i class="ph-plus ph-bold ph-lg"></i>
{{ i18n.ts.add }}</MkButton
>
<MkPagination <MkPagination
v-slot="{ items }"
ref="pagingComponent" ref="pagingComponent"
:pagination="pagination" :pagination="pagination"
class="list" class="list"
> >
<MkA <template #empty>
v-for="item in items" <MkInfo
:key="item.id" :icon="'paperclip'"
:to="`/clips/${item.id}`" :card="true"
class="item _panel _gap" >
> <p>{{ i18n.ts.clipsDesc }}</p>
<b>{{ item.name }}</b> </MkInfo>
<div v-if="item.description" class="description"> </template>
{{ item.description }} <template #default="{ items }">
</div> <MkA
</MkA> v-for="item in items"
:key="item.id"
:to="`/clips/${item.id}`"
class="item _panel _gap"
>
<b>{{ item.name }}</b>
<div v-if="item.description" class="description">
{{ item.description }}
</div>
</MkA>
</template>
</MkPagination> </MkPagination>
</div> </div>
</MkSpacer> </MkSpacer>
@ -40,6 +44,7 @@
import {} from "vue"; import {} from "vue";
import MkPagination from "@/components/MkPagination.vue"; import MkPagination from "@/components/MkPagination.vue";
import MkButton from "@/components/MkButton.vue"; import MkButton from "@/components/MkButton.vue";
import MkInfo from "@/components/MkInfo.vue";
import * as os from "@/os"; import * as os from "@/os";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
import { definePageMetadata } from "@/scripts/page-metadata"; import { definePageMetadata } from "@/scripts/page-metadata";
@ -100,10 +105,6 @@ definePageMetadata({
<style lang="scss" scoped> <style lang="scss" scoped>
.qtcaoidl { .qtcaoidl {
> .add {
margin: 0 auto 16px auto;
}
> .list { > .list {
> .item { > .item {
display: block; display: block;

View File

@ -8,16 +8,17 @@
/></template> /></template>
<MkSpacer :content-max="700"> <MkSpacer :content-max="700">
<div class="qkcjvfiv"> <div class="qkcjvfiv">
<div class="buttonWrapper"> <MkInfo
class="_gap"
:icon="'list-bullets'"
:card="true"
>
<p>{{ i18n.ts.listsDesc }}</p>
<MkButton primary class="add" @click="create" <MkButton primary class="add" @click="create"
><i class="ph-plus ph-bold ph-lg"></i> ><i class="ph-plus ph-bold ph-lg"></i>
{{ i18n.ts.createList }}</MkButton {{ i18n.ts.createList }}</MkButton
> >
<MkButton @click="deleteAll" </MkInfo>
><i class="ph-trash ph-bold ph-lg"></i>
{{ i18n.ts.deleteAll }}</MkButton
>
</div>
<MkPagination <MkPagination
v-slot="{ items }" v-slot="{ items }"
@ -34,6 +35,10 @@
<div class="name">{{ list.name }}</div> <div class="name">{{ list.name }}</div>
<MkAvatars :user-ids="list.userIds" /> <MkAvatars :user-ids="list.userIds" />
</MkA> </MkA>
<MkButton @click="deleteAll"
><i class="ph-trash ph-bold ph-lg"></i>
{{ i18n.ts.deleteAll }}</MkButton
>
</MkPagination> </MkPagination>
</div> </div>
</MkSpacer> </MkSpacer>
@ -45,6 +50,7 @@ import {} from "vue";
import MkPagination from "@/components/MkPagination.vue"; import MkPagination from "@/components/MkPagination.vue";
import MkButton from "@/components/MkButton.vue"; import MkButton from "@/components/MkButton.vue";
import MkAvatars from "@/components/MkAvatars.vue"; import MkAvatars from "@/components/MkAvatars.vue";
import MkInfo from "@/components/MkInfo.vue";
import * as os from "@/os"; import * as os from "@/os";
import { i18n } from "@/i18n"; import { i18n } from "@/i18n";
import { definePageMetadata } from "@/scripts/page-metadata"; import { definePageMetadata } from "@/scripts/page-metadata";
@ -92,15 +98,6 @@ definePageMetadata({
<style lang="scss" scoped> <style lang="scss" scoped>
.qkcjvfiv { .qkcjvfiv {
> .buttonWrapper {
display: grid;
justify-content: center;
> .add {
margin: 0 auto var(--margin) auto;
}
}
> .lists { > .lists {
> .list { > .list {
display: block; display: block;

View File

@ -26,6 +26,26 @@ export const defaultStore = markRaw(
where: "account", where: "account",
default: 0, default: 0,
}, },
tlHomeHintClosed: {
where: "device",
default: false,
},
tlLocalHintClosed: {
where: "device",
default: false,
},
tlRecommendedHintClosed: {
where: "device",
default: false,
},
tlSocialHintClosed: {
where: "device",
default: false,
},
tlGlobalHintClosed: {
where: "device",
default: false,
},
keepCw: { keepCw: {
where: "account", where: "account",
default: true, default: true,

View File

@ -303,6 +303,9 @@ hr {
._gap { ._gap {
margin: var(--margin) 0; margin: var(--margin) 0;
&:first-child {
margin-top: 0;
}
} }
// TODO: 廃止 // TODO: 廃止