Browse Source

feat(styles): integrate SCSS for improved styling and add page title management

- Added SCSS support with new global and common stylesheets.
- Introduced markdown styling for enhanced content presentation.
- Implemented a `usePageTitle` composable for dynamic document title management across various pages.
- Updated multiple pages to utilize the new title management system, improving SEO and user experience.

This update enhances the overall styling and usability of the application.
tags/邮箱功能前置
npmrun 6 months ago
parent
commit
b65ceefbee
  1. 6
      app/app.vue
  2. 2
      app/assets/scss/common.scss
  3. 0
      app/assets/scss/global.scss
  4. 306
      app/assets/scss/markdown/green.scss
  5. 454
      app/assets/scss/markdown/reset.scss
  6. 28
      app/composables/usePageTitle.ts
  7. 6
      app/pages/@[publicSlug]/about/index.vue
  8. 13
      app/pages/@[publicSlug]/index.vue
  9. 11
      app/pages/@[publicSlug]/posts/[postSlug].vue
  10. 10
      app/pages/@[publicSlug]/posts/index.vue
  11. 10
      app/pages/@[publicSlug]/reading/index.vue
  12. 10
      app/pages/@[publicSlug]/timeline/index.vue
  13. 4
      app/pages/discover/index.vue
  14. 2
      app/pages/index/index.vue
  15. 3
      app/pages/login/index.vue
  16. 2
      app/pages/me/admin/config/index.vue
  17. 2
      app/pages/me/admin/media-storage.vue
  18. 2
      app/pages/me/admin/users/index.vue
  19. 6
      app/pages/me/index.vue
  20. 4
      app/pages/me/media.vue
  21. 2
      app/pages/me/media/index.vue
  22. 2
      app/pages/me/media/orphans.vue
  23. 7
      app/pages/me/posts/[id].vue
  24. 2
      app/pages/me/posts/index.vue
  25. 2
      app/pages/me/posts/new.vue
  26. 2
      app/pages/me/profile/index.vue
  27. 2
      app/pages/me/rss/index.vue
  28. 2
      app/pages/me/timeline/index.vue
  29. 18
      app/pages/p/[publicSlug]/t/[shareToken].vue
  30. 3
      app/pages/register/index.vue
  31. 41
      bun.lock
  32. 1
      package.json
  33. BIN
      packages/drizzle-pkg/db.sqlite

6
app/app.vue

@ -4,3 +4,9 @@
<NuxtPage />
</NuxtLayout>
</template>
<style lang="scss">
// 写在nuxt.config.ts的css中会导致样式覆盖问题
@use "~/assets/scss/global.scss";
@use "~/assets/scss/common.scss";
</style>

2
app/assets/scss/common.scss

@ -0,0 +1,2 @@
@use "./markdown/reset.scss";
@use "./markdown/green.scss";

0
app/assets/scss/global.scss

306
app/assets/scss/markdown/green.scss

@ -0,0 +1,306 @@
@mixin chinese() {
&.chinese {
text-indent: 1.5em;
font-weight: 300;
h1,
h2,
h3,
h4,
h5,
h6,
ol,
ul,
blockquote,
details,
summary,
pre,
.tabs {
text-indent: 0;
}
}
}
.markdown-body {
--color-base: #ef4444;
--markdown-bg: white;
--color-bg: #ff47479c;
--color-light: #ef44441a;
--color-extra: rgba(239, 68, 68, 0.3);
--color-more: rgba(239, 68, 68, 0.4);
}
.markdown-body.green {
background-color: var(--markdown-bg);
@apply p-3 lg:p-6;
strong {
&::before{
content: "『";
}
&::after{
content: "』";
}
// color: #ff4d20;
}
/* 块/段落引用 */
// blockquote {
// position: relative;
// // color: #555;
// font-weight: 400;
// border-left: 6px solid var(--color-base);
// padding-left: 1em;
// margin-left: 0;
// padding: 1em;
// background-color: var(--color-light);
// }
blockquote {
position: relative;
z-index: 600;
padding: 20px 20px 15px 20px;
line-height: 1.4 !important;
background-color: rgba(239, 68, 68, 0.06);
border-radius: .4em;
> * {
position: relative;
&:first-child:before {
content: '\201C';
color: var(--color-light);
font-size: 6.5em;
font-weight: 700;
transform: rotate(15deg) translateX(-10px);
opacity: 1;
position: absolute;
top: -.4em;
left: -.2em;
text-shadow: none;
z-index: -10;
}
}
}
.tabs{
margin-top: 0;
margin-bottom: 1em;
}
/* 让链接在 hover 状态下显示下划线 */
// a {
// color: var(--color-base);
// text-decoration: none;
// &:hover {
// text-decoration: underline;
// }
// }
a {
position: relative;
z-index: 10;
transition: color 0.3s linear;
cursor: pointer;
font-weight: bolder;
// text-decoration: underline #c7254e;
text-decoration: none;
color: var(--color-base);
border-bottom: 1px solid currentColor;
padding: 0 4px;
&[data-footnote-backref],
&[data-footnote-ref] {
// text-decoration: none;
border: none;
&:hover {
background: none;
animation: none;
}
}
&:hover {
content: '';
// text-decoration: none;
border: none;
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 4'%3E%3Cpath fill='none' stroke='%23ff4d20' d='M0 3.5c5 0 5-3 10-3s5 3 10 3 5-3 10-3 5 3 10 3'/%3E%3C/svg%3E")
repeat-x 0 100%;
background-size: 20px auto;
animation: waveMove 1s infinite linear;
}
@keyframes waveMove {
0% {
background-position: 0 100%;
}
100% {
background-position: -20px 100%;
}
}
}
// 由prism.scss处理了
pre {
background: var(--prism-background);
font-size: var(--prism-font-size);
// /* border: 1px solid #ddd; */
// padding: 1em 1.5em;
display: block;
-webkit-overflow-scrolling: touch;
}
pre,
pre code {
font-family: var(--prism-font-family);
}
// /* 底部印刷体、版本等标记 */
small,
/* 图片说明 */
figcaption {
font-size: 0.75em;
color: #888;
}
// .markdown-body {
legend {
color: #000;
font-weight: inherit;
}
caption {
color: #000;
font-weight: inherit;
}
del {
text-decoration: line-through var(--color-base) 2px;
}
code {
color: rgb(45, 55, 72);
background-color: rgba(160,174,192,0.25);
font-family: inherit;
font-size: 1em;
// color: #ffffff;
// background-color: #ff4c209c;
border-radius: 4px;
padding: 1px 6px;
// font-size: 0.875em;
// font-size: 1.0769em;
// position: relative;
// top: 0.1em;
margin: 0 2px;
vertical-align: bottom;
}
pre {
code {
padding: 0;
font-size: inherit;
font-weight: inherit;
color: inherit;
white-space: pre;
background-color: transparent;
vertical-align: baseline;
border-radius: 0;
margin: 0;
}
}
table {
width: 100%;
display: table;
border: 1px solid var(--color-light);
tr:hover {
background: var(--color-light);
}
&:hover{
border: 1px solid var(--color-extra);
th {
border-right: 1px solid var(--color-extra);
background: var(--color-extra);
border-bottom: 1px solid var(--color-extra);
}
td {
border-right: 1px solid var(--color-extra);
}
caption {
border-right: 1px solid var(--color-extra);
}
thead {
th {
background: var(--color-extra);
}
}
}
// table-layout: fixed;
th {
border-right: 1px solid var(--color-light);
padding: 0.5em 1em;
background: var(--color-light);
border-bottom: 1px solid var(--color-light);
}
td {
border-right: 1px solid var(--color-light);
padding: 0.5em 1em;
}
caption {
border-right: 1px solid var(--color-light);
padding: 0.5em 1em;
border-bottom: none;
}
thead {
th {
background: var(--color-extra);
}
}
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 1.2em;
margin-bottom: 0.6em;
line-height: 1.35;
position: relative;
}
h1 {
font-size: 1.8em;
}
h2 {
font-size: 1.6em;
}
h3 {
font-size: 1.4em;
}
h4 {
font-size: 1.2em;
}
h5 {
font-size: 1em;
}
h6 {
font-size: 1em;
}
::-webkit-calendar-picker-indicator {
filter: invert(50%);
}
em {
// color: #000;
font-weight: inherit;
position: relative;
&:after {
position: absolute;
top: 0.65em;
left: 0;
width: 100%;
overflow: hidden;
white-space: nowrap;
pointer-events: none;
color: var(--color-base);
content: '・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・';
}
}
ul.toc {
li {
list-style-type: none;
a {
text-decoration: none;
border: 0;
list-style-type: none;
}
}
}
@include chinese;
}

454
app/assets/scss/markdown/reset.scss

@ -0,0 +1,454 @@
// https://verytoolz.com/blog/03bfb3598f/
.markdown-body {
--color-fg-default: #24292f; // 文本色-默认
--color-fg-muted: #57606a; // 文本色-柔和
--color-fg-subtle: #6e7781; // 文本色-微妙
--color-canvas-default: #ffffff; // 底色-默认
--color-canvas-subtle: #f6f8fa; // 底色-微妙
--color-border-default: #d0d7de; // 边框色-默认
--color-border-muted: hsla(210, 18%, 87%, 1); // 边框色-柔和
--color-neutral-muted: rgba(175, 184, 193, 0.2); // 边框色-中性
--color-accent-fg: #0969da; // 文本强调色
--color-accent-emphasis: #0969da; // 背景强调色
--color-attention-subtle: #fff8c5; // 背景注意色
--color-danger-fg: #cf222e; // 文本危险色
--color-mark-default: rgb(255, 255, 0); // mark 默认色
--color-mark-fg: rgb(255, 187, 0); // mark 强调色
}
.markdown-body {
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
text-rendering: optimizelegibility;
margin: 0;
word-wrap: break-word;
color: var(--color-fg-muted);
&::before {
display: table;
content: '';
}
&::after {
display: table;
clear: both;
content: '';
}
> *:first-child {
margin-top: 0 !important;
}
> *:last-child {
margin-bottom: 0 !important;
}
p,
blockquote,
ul,
ol,
dl,
table,
hr,
form,
pre,
details {
margin-top: 0;
margin-bottom: 1em;
}
blockquote {
& > :first-child {
margin-top: 0;
}
& > :last-child {
margin-bottom: 0;
}
}
/* 统一显示成块状元素 */
details,
figcaption,
figure {
display: block;
}
/* HTML5 媒体文件跟 img 保持一致 */
audio,
canvas,
video {
display: inline-block;
}
/* 按钮内部间距统一 */
button::-moz-focus-inner,
input::-moz-focus-inner {
padding: 0;
border: 0;
}
/* 定义元素显示为斜体 */
dfn {
font-style: italic;
}
/* 去掉各Table cell 的边距并让其边重合 */
table {
border-collapse: collapse;
border-spacing: 0;
display: block;
width: max-content;
max-width: 100%;
overflow: auto;
}
/* 可拖动文件添加拖动手势 */
[draggable] {
cursor: move;
}
/* 加粗元素 */
b,
strong {
font-weight: var(--base-text-weight-semibold, 600);
}
/* 缩写元素样式统一 */
abbr,
acronym {
border-bottom: none;
font-variant: normal;
text-decoration: underline dotted;
}
/* 添加鼠标问号,进一步确保应用的语义是正确的(要知道,交互他们也有洁癖,如果你不去掉,那得多花点口舌) */
abbr {
cursor: help;
}
/* 一致的 del 样式 */
del {
text-decoration: line-through;
}
/* a标签去除下划线 */
a {
text-decoration: none;
&:not([href]) {
color: inherit;
text-decoration: none;
}
&:hover {
text-decoration: underline;
}
}
/* 默认不显示下划线,保持页面简洁 */
ins {
text-decoration: none;
}
/* 专名号:虽然 u 已经重回 html5 Draft,但在所有浏览器中都是可以使用的,
* 要做到更好,向后兼容的话,添加 class="typo-u" 来显示专名号
* 关于 <u> 标签:http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-u-element
* 被放弃的是 4,之前一直搞错 http://www.w3.org/TR/html401/appendix/changes.html#idx-deprecated
* 一篇关于 <u> 标签的很好文章:http://html5doctor.com/u-element/
*/
u,
.typo-u {
text-decoration: underline;
}
/* 隐藏指定元素 */
[hidden] {
display: none !important;
}
/* 伸缩框显示为列表元素 */
summary {
display: list-item;
}
q:before,
q:after {
content: '';
}
caption,
th {
text-align: left;
}
caption[align='center'],
th[align='center'] {
text-align: center;
}
address,
caption,
cite,
em,
th,
var {
font-weight: 400;
}
/* 标记,类似于手写的荧光笔的作用 */
mark {
background: var(--color-mark-default);
// background: #fffdd1;
// border-bottom: 1px solid #ffedce;
padding: 2px;
&.active{
background: var(--color-mark-fg);
}
// margin: 0 5px;
}
/* 统一h1元素的间隔和字体大小 */
h1 {
margin: 0.67em 0;
font-weight: var(--base-text-weight-semibold, 600);
font-size: 2em;
}
/* small字体缩小 */
small {
font-size: 90%;
}
/* 上下标显示 */
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub a,
sup a {
padding: 0 0.1em;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* 代码相关的字体大小统一 */
code,
kbd,
pre,
samp,
pre tt {
font-family: monospace;
font-size: 1em;
}
/* 去除默认边框 */
fieldset,
img {
border: 0;
}
/* 图片初始化样式 */
img {
border-style: none;
max-width: 100%;
box-sizing: content-box;
margin: 0 auto;
background-color: var(--color-canvas-default);
}
/* 可附标题内容元素的间距 */
figure {
margin: 1em 40px;
}
/* 间隔线 */
/* 一致化 horizontal rule */
hr {
box-sizing: content-box;
overflow: hidden;
background: transparent;
border-bottom: 1px solid var(--color-border-muted);
height: 0.25em;
padding: 0;
margin: 24px 0;
background-color: var(--color-border-default);
border: 0;
&::before {
display: table;
content: '';
}
&::after {
display: table;
clear: both;
content: '';
}
}
/* 表单元素并不继承父级 font 的问题 */
button,
input,
select,
textarea {
font: inherit;
margin: 0;
overflow: visible;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
/* 外观显示为按钮 */
[type='button'],
[type='reset'],
[type='submit'] {
-webkit-appearance: button;
}
/* 这两个表单样式规则覆盖 */
[type='checkbox'],
[type='radio'] {
box-sizing: border-box;
padding: 0;
}
/* 数字按钮内部高度自动 */
[type='number']::-webkit-inner-spin-button,
[type='number']::-webkit-outer-spin-button {
height: auto;
}
/* 搜索按钮内图标外观去除 */
[type='search']::-webkit-search-cancel-button,
[type='search']::-webkit-search-decoration {
-webkit-appearance: none;
}
/* 输入框的占位符样式 */
::-webkit-input-placeholder {
color: inherit;
opacity: 0.54;
}
/* 文件选择按钮样式统一 */
::-webkit-file-upload-button {
-webkit-appearance: button;
font: inherit;
}
/* 占位符显示统一 */
::placeholder {
color: var(--color-fg-subtle);
opacity: 1;
}
/* table内的td,th去除留白 */
td,
th {
padding: 0;
}
/* 伸缩框鼠标显示 */
details summary {
cursor: pointer;
}
details:not([open]) > *:not(summary) {
display: none !important;
}
/* 按键显示 */
kbd {
display: inline-block;
padding: 3px 5px;
font: 11px ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas,
Liberation Mono, monospace;
line-height: 10px;
color: var(--color-fg-default);
vertical-align: middle;
background-color: var(--color-canvas-subtle);
border: solid 1px var(--color-neutral-muted);
border-bottom-color: var(--color-neutral-muted);
border-radius: 6px;
box-shadow: inset 0 -1px 0 var(--color-neutral-muted);
}
.clearfix:before,
.clearfix:after {
content: '';
display: table;
}
.clearfix:after {
clear: both;
}
.clearfix {
zoom: 1;
}
/* 强制文本换行 */
.textwrap,
.textwrap td,
.textwrap th {
word-wrap: break-word;
word-break: break-all;
}
.textwrap-table {
table-layout: fixed;
}
ul {
margin-left: 0;
padding-left: 0;
margin-left: 2em;
list-style: disc;
}
ol {
margin-left: 0;
padding-left: 0;
margin-left: 2em;
list-style: decimal;
li {
padding-left: 0.4em;
}
}
li + li {
margin-top: 0.25em;
}
li {
ul {
margin-bottom: 0.8em;
margin-left: 2em;
list-style: circle;
li {
ul {
list-style: square;
}
}
}
ol {
margin-bottom: 0.8em;
margin-left: 2em;
}
}
.task-list-item {
list-style-type: none;
position: relative;
> input {
&:nth-child(1) {
margin-right: 6px;
}
}
label {
font-weight: 400;
}
.handle {
display: none;
}
input[type='checkbox'] {
width: 0.9em;
height: 0.9em;
position: absolute;
left: -1.3em;
top: 0.35em;
}
}
.task-list-item.enabled {
label {
cursor: pointer;
}
}
.task-list-item + .task-list-item {
margin-top: 3px;
}
.contains-task-list {
// margin-left: 0.6em;
&:dir(rtl) {
.task-list-item {
input[type='checkbox'] {
margin: 0 -1.6em 0.25em 0.2em;
}
}
}
}
.toc{
margin-left: 0;
}
dl {
display: block;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0px;
margin-inline-end: 0px;
unicode-bidi: isolate;
dt {
display: block;
unicode-bidi: isolate;
}
dd {
display: block;
margin-inline-start: 40px;
unicode-bidi: isolate;
}
}
}

28
app/composables/usePageTitle.ts

@ -0,0 +1,28 @@
import type { MaybeRefOrGetter } from 'vue'
import { toValue } from 'vue'
/**
* 统一设置 document title:`片段 · … · 站点名`(站点名来自后台 `siteName`)。
*/
export function usePageTitle(
parts: MaybeRefOrGetter<readonly (string | null | undefined)[] | string | null | undefined>,
) {
const { siteName } = useGlobalConfig()
useHead(() => {
const raw = toValue(parts)
const list: (string | null | undefined)[] = Array.isArray(raw)
? [...raw]
: [raw]
const cleaned = list
.map((s) => (typeof s === 'string' ? s.trim() : ''))
.filter((s) => s.length > 0)
const site = siteName.value.trim() || 'Person Panel'
const prefix = cleaned.join(' · ')
return {
title: prefix ? `${prefix} · ${site}` : site,
}
})
}

6
app/pages/@[publicSlug]/about/index.vue

@ -31,9 +31,9 @@ const displayName = computed(
() => data.value?.user.nickname || data.value?.user.publicSlug || slug.value,
)
useHead(() => ({
title: data.value ? `${displayName.value} · 关于` : '关于',
}))
usePageTitle(() =>
data.value ? [displayName.value, '关于'] : [slug.value, '关于'],
)
</script>
<template>

13
app/pages/@[publicSlug]/index.vue

@ -145,6 +145,19 @@ const showBioReadMore = computed(() => {
}
return stripFrontMatter(md).trim().length > 0
})
usePageTitle(() => {
const s = slug.value
const d = data.value
if (!d) {
return [`@${s}`, '主页']
}
const name =
d.user.nickname
|| (d.user.publicSlug ? `@${d.user.publicSlug}` : '')
|| s
return [name, '主页']
})
</script>
<template>

11
app/pages/@[publicSlug]/posts/[postSlug].vue

@ -54,10 +54,13 @@ const publishedAtIso = computed(() =>
data.value?.publishedAt != null ? occurredOnToIsoAttr(data.value.publishedAt) : '',
)
watchEffect(() => {
if (data.value?.title) {
useHead({ title: data.value.title })
usePageTitle(() => {
const ps = publicSlug.value
const t = data.value?.title?.trim()
if (!t) {
return ['文章', `@${ps}`]
}
return [t, `@${ps}`]
})
onMounted(() => {
@ -117,7 +120,7 @@ const editPostHref = computed(() =>
{{ leadSummary }}
</p>
<article
class="prose dark:prose-invert max-w-none prose-a:text-primary prose-img:rounded-lg"
class="prose dark:prose-invert max-w-none prose-a:text-primary prose-img:rounded-lg markdown-body green"
v-html="renderedBody"
/>
<PostComments mode="public-post" :public-slug="publicSlug" :post-slug="postSlug" />

10
app/pages/@[publicSlug]/posts/index.vue

@ -7,7 +7,6 @@ import {
definePageMeta({
layout: 'public',
title: '文章',
})
const route = useRoute()
@ -73,6 +72,15 @@ const { data, pending, error } = await useAsyncData(
},
{ watch: [slug, page] },
)
usePageTitle(() => {
const parts: string[] = []
if (page.value > 1) {
parts.push(`第 ${page.value} 页`)
}
parts.push('文章', `@${slug.value}`)
return parts
})
</script>
<template>

10
app/pages/@[publicSlug]/reading/index.vue

@ -3,7 +3,6 @@ import { unwrapApiBody, type ApiResponse } from '../../../utils/http/factory'
definePageMeta({
layout: 'public',
title: '阅读',
})
const route = useRoute()
@ -85,6 +84,15 @@ const { data, pending, error } = await useAsyncData(
},
{ watch: [slug, page] },
)
usePageTitle(() => {
const parts: string[] = []
if (page.value > 1) {
parts.push(`第 ${page.value} 页`)
}
parts.push('阅读', `@${slug.value}`)
return parts
})
</script>
<template>

10
app/pages/@[publicSlug]/timeline/index.vue

@ -7,7 +7,6 @@ import {
definePageMeta({
layout: 'public',
title: '时光机',
})
const route = useRoute()
@ -77,6 +76,15 @@ const { data, pending, error } = await useAsyncData(
},
{ watch: [slug, page] },
)
usePageTitle(() => {
const parts: string[] = []
if (page.value > 1) {
parts.push(`第 ${page.value} 页`)
}
parts.push('时光机', `@${slug.value}`)
return parts
})
</script>
<template>

4
app/pages/discover/index.vue

@ -1,6 +1,4 @@
<script setup lang="ts">
definePageMeta({ title: '发现' })
const route = useRoute()
const router = useRouter()
const { fetchData, getApiErrorMessage } = useClientApi()
@ -80,6 +78,8 @@ function onPageChange(p: number) {
onMounted(() => {
void load()
})
usePageTitle(() => (page.value > 1 ? [`第 ${page.value} 页`, '发现'] : ['发现']))
</script>
<template>

2
app/pages/index/index.vue

@ -5,6 +5,8 @@ const { loggedIn, user, clear } = useAuthSession()
const { fetchData } = useClientApi()
const { allowRegister, siteName } = useGlobalConfig()
usePageTitle('首页')
const logoutLoading = ref(false)
const features = [

3
app/pages/login/index.vue

@ -4,10 +4,11 @@ import { DEFAULT_AUTHENTICATED_LANDING_PATH, normalizeSafeRedirect } from '../..
import { useAuthSession } from '../../composables/useAuthSession'
definePageMeta({
title: '登录',
layout: 'blank',
})
usePageTitle('登录')
type LoginFormState = {
username: string
password: string

2
app/pages/me/admin/config/index.vue

@ -1,7 +1,7 @@
<script setup lang="ts">
import { useAuthSession } from '../../../../composables/useAuthSession'
definePageMeta({ title: '应用配置' })
usePageTitle('应用配置')
type GlobalConfigPayload = {
config: {

2
app/pages/me/admin/media-storage.vue

@ -1,7 +1,7 @@
<script setup lang="ts">
import { useAuthSession } from '../../../composables/useAuthSession'
definePageMeta({ title: '媒体存储校验' })
usePageTitle('媒体存储校验')
type RefDetail = { ownerType: string; ownerId: number }

2
app/pages/me/admin/users/index.vue

@ -2,7 +2,7 @@
import { useAuthSession } from '../../../../composables/useAuthSession'
import { buildPublicProfileAbsoluteUrl } from '../../../../utils/public-profile-url'
definePageMeta({ title: '用户管理' })
usePageTitle('用户管理')
const { user, refresh } = useAuthSession()
const { fetchData } = useClientApi()

6
app/pages/me/index.vue

@ -1,11 +1,9 @@
<script setup lang="ts">
import { useAuthSession } from '../../composables/useAuthSession'
definePageMeta({
title: '我的',
})
const { user } = useAuthSession()
usePageTitle('控制台')
const { fetchData } = useClientApi()
type ProfilePayload = {

4
app/pages/me/media.vue

@ -1,8 +1,8 @@
<script setup lang="ts">
definePageMeta({ title: '媒体' })
const route = useRoute()
usePageTitle('媒体')
function tabActive(to: string): boolean {
const p = route.path
if (to === '/me/media') {

2
app/pages/me/media/index.vue

@ -1,7 +1,7 @@
<script setup lang="ts">
import { useAuthSession } from '../../../composables/useAuthSession'
definePageMeta({ title: '媒体库' })
usePageTitle('媒体库')
type RefContext = {
ownerType: string

2
app/pages/me/media/orphans.vue

@ -1,7 +1,7 @@
<script setup lang="ts">
import { useAuthSession } from '../../../composables/useAuthSession'
definePageMeta({ title: '图片孤儿审查' })
usePageTitle('图片孤儿审查')
type OrphanItem = {
id: number

7
app/pages/me/posts/[id].vue

@ -1,8 +1,6 @@
<script setup lang="ts">
import { useAuthSession } from '../../../composables/useAuthSession'
definePageMeta({ title: '编辑文章' })
const route = useRoute()
const id = computed(() => route.params.id as string)
const { user, refresh: refreshAuth } = useAuthSession()
@ -59,6 +57,11 @@ watch(id, () => {
void load()
})
usePageTitle(() => {
const t = state.title.trim()
return t ? [t, '编辑'] : ['编辑文章']
})
async function save() {
saving.value = true
try {

2
app/pages/me/posts/index.vue

@ -1,7 +1,7 @@
<script setup lang="ts">
import { useAuthSession } from '../../../composables/useAuthSession'
definePageMeta({ title: '文章' })
usePageTitle('我的文章')
type Row = { id: number; title: string; slug: string; visibility: string }

2
app/pages/me/posts/new.vue

@ -1,5 +1,5 @@
<script setup lang="ts">
definePageMeta({ title: '新建文章' })
usePageTitle('新建文章')
const { fetchData } = useClientApi()
const toast = useToast()

2
app/pages/me/profile/index.vue

@ -1,7 +1,7 @@
<script setup lang="ts">
import { useAuthSession } from '../../../composables/useAuthSession'
definePageMeta({ title: '资料' })
usePageTitle('个人资料')
const { refresh: refreshAuthSession } = useAuthSession()
const { fetchData, getApiErrorMessage } = useClientApi()

2
app/pages/me/rss/index.vue

@ -1,5 +1,5 @@
<script setup lang="ts">
definePageMeta({ title: 'RSS' })
usePageTitle('RSS 收件箱')
type Feed = {
id: number

2
app/pages/me/timeline/index.vue

@ -7,7 +7,7 @@ import {
parseLocalDatetimeInput,
} from '../../../utils/timeline-datetime'
definePageMeta({ title: '时光机' })
usePageTitle('时光机')
const { user } = useAuthSession()
const requestUrl = useRequestURL()

18
app/pages/p/[publicSlug]/t/[shareToken].vue

@ -26,6 +26,24 @@ const { data, pending, error } = await useAsyncData(
{ watch: [publicSlug, shareToken] },
)
usePageTitle(() => {
const s = publicSlug.value
const d = data.value
if (!d) {
return ['仅链接分享', `@${s}`]
}
if (d.kind === 'post') {
const t = String(d.data.title ?? '').trim() || '文章'
return [t, '仅链接', `@${s}`]
}
if (d.kind === 'timeline') {
const t = String(d.data.title ?? '').trim() || '时光条目'
return [t, '仅链接', `@${s}`]
}
const t = String(d.data.title ?? '').trim() || '阅读条目'
return [t, '仅链接', `@${s}`]
})
const renderedUnlistedPostBody = computed(() => {
if (data.value?.kind !== 'post') {
return ''

3
app/pages/register/index.vue

@ -3,7 +3,6 @@ import type { FormError, FormSubmitEvent } from '@nuxt/ui'
import { normalizeSafeRedirect } from '../../utils/auth-routes'
definePageMeta({
title: '注册',
layout: 'blank',
middleware: [
async () => {
@ -16,6 +15,8 @@ definePageMeta({
],
})
usePageTitle('注册')
type RegisterFormState = {
username: string
password: string

41
bun.lock

@ -39,6 +39,7 @@
"@types/pg": "8.20.0",
"bun-types": "1.3.12",
"drizzle-kit": "0.31.10",
"sass": "^1.99.0",
"tsx": "4.21.0",
"typescript": "6.0.2",
},
@ -1027,7 +1028,7 @@
"caniuse-lite": ["caniuse-lite@1.0.30001787", "", {}, "sha512-mNcrMN9KeI68u7muanUpEejSLghOKlVhRqS/Za2IeyGllJ9I9otGpR9g3nsw7n4W378TE/LyIteA0+/FOZm4Kg=="],
"chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="],
@ -1349,6 +1350,8 @@
"image-meta": ["image-meta@0.2.2", "", {}, "sha512-3MOLanc3sb3LNGWQl1RlQlNWURE5g32aUphrDyFeCsxBTk08iE3VNe4CwsUZ0Qs1X+EfX0+r29Sxdpza4B+yRA=="],
"immutable": ["immutable@5.1.5", "", {}, "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A=="],
"impound": ["impound@1.1.5", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.31", "es-module-lexer": "^2.0.0", "pathe": "^2.0.3", "unplugin": "^3.0.0", "unplugin-utils": "^0.3.1" } }, "sha512-5AUn+QE0UofqNHu5f2Skf6Svukdg4ehOIq8O0EtqIx4jta0CDZYBPqpIHt0zrlUTiFVYlLpeH39DoikXBjPKpA=="],
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
@ -1809,7 +1812,7 @@
"readdir-glob": ["readdir-glob@1.1.3", "", { "dependencies": { "minimatch": "^5.1.0" } }, "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA=="],
"readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"redis-errors": ["redis-errors@1.2.0", "", {}, "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w=="],
@ -1847,6 +1850,8 @@
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
"sass": ["sass@1.99.0", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q=="],
"sax": ["sax@1.6.0", "", {}, "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA=="],
"saxes": ["saxes@6.0.0", "", { "dependencies": { "xmlchars": "^2.2.0" } }, "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA=="],
@ -2161,6 +2166,8 @@
"@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@dxup/nuxt/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
"@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
@ -2229,6 +2236,8 @@
"archiver-utils/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="],
"c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"compress-commons/is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="],
"compress-commons/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="],
@ -2259,12 +2268,16 @@
"mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
"nitropack/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"nitropack/esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="],
"nitropack/hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
"npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
"nuxt/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
"prosemirror-trailing-node/escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="],
@ -2297,6 +2310,10 @@
"unplugin-auto-import/unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
"unplugin-vue-components/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"unstorage/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"untun/citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="],
"untun/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
@ -2309,10 +2326,10 @@
"vite-dev-rpc/birpc": ["birpc@2.9.0", "", {}, "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw=="],
"vite-plugin-checker/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
"vite-plugin-checker/npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="],
"vue-router/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
@ -2323,6 +2340,8 @@
"zip-stream/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="],
"@dxup/nuxt/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
@ -2389,6 +2408,8 @@
"archiver/readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
"c12/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"compress-commons/readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
"crc32-stream/readable-stream/buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
@ -2457,6 +2478,8 @@
"mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
"nitropack/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"nitropack/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="],
"nitropack/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="],
@ -2509,6 +2532,8 @@
"nitropack/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="],
"nuxt/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"readdir-glob/minimatch/brace-expansion": ["brace-expansion@2.0.3", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA=="],
"rollup-plugin-visualizer/open/wsl-utils": ["wsl-utils@0.3.1", "", { "dependencies": { "is-wsl": "^3.1.0", "powershell-utils": "^0.1.0" } }, "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg=="],
@ -2569,14 +2594,16 @@
"tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="],
"unplugin-vue-components/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"unstorage/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"vaul-vue/@vueuse/core/@types/web-bluetooth": ["@types/web-bluetooth@0.0.20", "", {}, "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow=="],
"vaul-vue/@vueuse/core/@vueuse/metadata": ["@vueuse/metadata@10.11.1", "", {}, "sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw=="],
"vaul-vue/@vueuse/core/@vueuse/shared": ["@vueuse/shared@10.11.1", "", { "dependencies": { "vue-demi": ">=0.14.8" } }, "sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA=="],
"vite-plugin-checker/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
"vite-plugin-checker/npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="],
"vite-plugin-checker/npm-run-path/unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="],
@ -2633,6 +2660,8 @@
"vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="],
"vue-router/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="],
"wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],

1
package.json

@ -53,6 +53,7 @@
"@types/pg": "8.20.0",
"bun-types": "1.3.12",
"drizzle-kit": "0.31.10",
"sass": "^1.99.0",
"tsx": "4.21.0",
"typescript": "6.0.2"
}

BIN
packages/drizzle-pkg/db.sqlite

Binary file not shown.
Loading…
Cancel
Save