feat: squash all the commits for hiding some sensitive information.
2
.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
dist
|
25
.editorconfig
Normal file
@ -0,0 +1,25 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{md,mdx}]
|
||||
indent_size = tab
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{js,jsx,ts,tsx,css,less,sass,scss}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.{yml,yaml,json}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
|
||||
[Makefile]
|
||||
indent_size = tab
|
17
.env.example
Normal file
@ -0,0 +1,17 @@
|
||||
# Since the ".env" file is gitignored, you can use the ".env.example" file to
|
||||
# build a new ".env" file when you clone the repo. Keep this file up-to-date
|
||||
# when you add new variables to `.env`.
|
||||
|
||||
# This file will be committed to version control, so make sure not to have any
|
||||
# secrets in it. If you are cloning this repo, create a copy of this file named
|
||||
# ".env" and populate it with your secrets.
|
||||
|
||||
# PostgreSQL configuration.
|
||||
POSTGRES_HOST=
|
||||
POSTGRES_PORT=
|
||||
POSTGRES_USERNAME=
|
||||
POSTGRES_PASSWORD=
|
||||
POSTGRES_DATABASE=
|
||||
|
||||
# Artalk configuration
|
||||
ARTALK_HOST=
|
162
.gitattributes
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
# This file is inspired by https://github.com/alexkaratarakis/gitattributes
|
||||
#
|
||||
# Auto detect text files and perform LF normalization
|
||||
# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/
|
||||
* text=auto
|
||||
|
||||
# The above will handle all files NOT found below
|
||||
# These files are text and should be normalized (Convert crlf => lf)
|
||||
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
*.coffee text
|
||||
*.css text
|
||||
*.cql text
|
||||
*.df text
|
||||
*.ejs text
|
||||
*.html text
|
||||
*.java text
|
||||
*.js text
|
||||
*.json text
|
||||
*.less text
|
||||
*.properties text
|
||||
*.sass text
|
||||
*.scss text
|
||||
*.sh text
|
||||
*.sql text
|
||||
*.txt text
|
||||
*.ts text
|
||||
*.xml text
|
||||
*.yaml text
|
||||
*.yml text
|
||||
|
||||
# Documents
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
*.markdown text
|
||||
*.md text
|
||||
*.adoc text
|
||||
*.textile text
|
||||
*.mustache text
|
||||
*.csv text
|
||||
*.tab text
|
||||
*.tsv text
|
||||
*.txt text
|
||||
*.config text
|
||||
AUTHORS text
|
||||
CHANGELOG text
|
||||
CHANGES text
|
||||
CONTRIBUTING text
|
||||
COPYING text
|
||||
copyright text
|
||||
*COPYRIGHT* text
|
||||
INSTALL text
|
||||
license text
|
||||
LICENSE text
|
||||
NEWS text
|
||||
readme text
|
||||
*README* text
|
||||
TODO text
|
||||
Jenkinsfile text
|
||||
|
||||
# Graphics
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.tif binary
|
||||
*.tiff binary
|
||||
*.ico binary
|
||||
# SVG treated as an asset (binary) by default. If you want to treat it as text,
|
||||
# comment-out the following line and uncomment the line after.
|
||||
*.svg binary
|
||||
#*.svg text
|
||||
*.eps binary
|
||||
*.sketch binary
|
||||
|
||||
# These files are binary and should be left untouched
|
||||
# (binary is a macro for -text -diff)
|
||||
*.class binary
|
||||
*.jar binary
|
||||
*.war binary
|
||||
|
||||
## LINTERS
|
||||
.csslintrc text
|
||||
.eslintrc text
|
||||
.jscsrc text
|
||||
.jshintrc text
|
||||
.jshintignore text
|
||||
.stylelintrc text
|
||||
.prettierignore text
|
||||
.prettierrc text
|
||||
.scalafmt.conf text
|
||||
|
||||
## CONFIGS
|
||||
*.bowerrc text
|
||||
*.conf text
|
||||
*.config text
|
||||
.editorconfig text
|
||||
.gitattributes text
|
||||
.gitconfig text
|
||||
.gitignore text
|
||||
.htaccess text
|
||||
*.npmignore text
|
||||
|
||||
## HEROKU
|
||||
Procfile text
|
||||
.slugignore text
|
||||
|
||||
## AUDIO
|
||||
*.kar binary
|
||||
*.m4a binary
|
||||
*.mid binary
|
||||
*.midi binary
|
||||
*.mp3 binary
|
||||
*.ogg binary
|
||||
*.ra binary
|
||||
|
||||
## VIDEO
|
||||
*.3gpp binary
|
||||
*.3gp binary
|
||||
*.as binary
|
||||
*.asf binary
|
||||
*.asx binary
|
||||
*.fla binary
|
||||
*.flv binary
|
||||
*.m4v binary
|
||||
*.mng binary
|
||||
*.mov binary
|
||||
*.mp4 binary
|
||||
*.mpeg binary
|
||||
*.mpg binary
|
||||
*.swc binary
|
||||
*.swf binary
|
||||
*.webm binary
|
||||
|
||||
## ARCHIVES
|
||||
*.7z binary
|
||||
*.gz binary
|
||||
*.rar binary
|
||||
*.tar binary
|
||||
*.zip binary
|
||||
|
||||
## FONTS
|
||||
*.ttf binary
|
||||
*.eot binary
|
||||
*.otf binary
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
|
||||
## Bun
|
||||
*.lockb binary diff=lockb
|
||||
|
||||
## License File
|
||||
LICENSE.* text
|
29
.gitignore
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
# build output
|
||||
dist/
|
||||
.zeabur/
|
||||
|
||||
# generated types
|
||||
.astro/
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
.env.production
|
||||
|
||||
# macOS-specific files
|
||||
.DS_Store
|
||||
|
||||
# jetbrains setting folder
|
||||
!.idea/icon.svg
|
||||
.idea/
|
||||
|
||||
# Hide the SQL session
|
||||
*.session.sql
|
1
.husky/pre-commit
Normal file
@ -0,0 +1 @@
|
||||
npx lint-staged
|
12
.idea/icon.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="300px" height="300px" viewBox="0 0 300 300" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>favicon</title>
|
||||
<g id="favicon" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<rect fill="#263148" x="0" y="0" width="300" height="300" />
|
||||
<g id="logo-white" transform="translate(9, 3.888)">
|
||||
<path d="M159,154.195523 C167.013592,152.617424 174.05936,152.751451 180.129673,154.674602 C190.120795,157.839913 194.348511,161.02564 199.517296,168.40144 C202.925628,173.265093 205.718707,181.861769 208,194.149433 C202.817237,195.503225 198.494331,195.463815 195.074572,193.809733 C188.963104,190.853715 183.30068,186.732689 175.022826,177.505654 C169.768056,171.648346 164.430736,163.875789 159,154.195523 Z" id="font1-dot" fill="#EEB4B4" />
|
||||
<path d="M151.486676,25.701431 C155.616373,28.5082875 160.109234,31.601356 164.965286,34.9806001 C165.393463,35.2785613 165.822641,35.5757097 166.255249,35.8738863 L167.105716,36.458366 C168.619019,37.4954138 170.108644,38.5008303 171.499238,39.4303971 L172.608374,40.1697969 C174.26724,41.2727003 175.735093,42.2354804 176.860606,42.9690389 L176.448028,45.1207071 L166.710146,84.6326462 C180.591569,66.4261557 193.885083,57.2272012 206.997372,58.6211808 C208.743695,58.806834 210.475625,59.0033727 212.18144,59.2464237 C212.733943,59.3251464 213.291751,59.4029337 213.853878,59.4813177 C215.158468,59.6632319 216.474026,59.8465926 217.787079,60.0508718 L218.661915,60.1902579 C225.09927,61.241972 231.826526,62.8614549 236.986443,68.0144332 C240.889249,71.9119921 243.813448,77.8014483 245.23642,86.708071 C247.095663,98.3453903 243.120654,117.723729 238.770002,139.330906 L238.580551,140.271866 C237.890376,143.700241 237.191343,147.180322 236.50179,150.693982 L236.044022,153.039529 C235.556986,155.549827 235.077075,158.073824 234.610494,160.607168 L234.263405,162.507565 L233.922672,164.406776 C228.900089,192.67064 226.130123,221.241925 234.44056,240.371255 C240.652266,254.669635 245.935235,262.932333 250.296038,267.670416 C253.412465,271.056463 256.180453,272.79959 258.553083,273.698031 C262.383549,275.148509 265.383302,274.528886 267.668585,273.982958 C268.14919,273.865733 268.422366,273.767797 268.665926,273.767797 C271.112421,273.767797 275.809409,272.387068 282.731388,269.370175 C283.375366,277.48654 282.878184,284.333295 281.156359,289.899262 C280.659157,291.506519 280.558961,292.472131 279.535062,293.024782 C275.748117,295.068793 270.498503,293.963559 265.488631,292.694915 C256.722323,290.485677 244.816282,287.548472 234.696635,275.178958 C233.697221,273.957347 232.737161,272.794212 231.813783,271.675534 C222.758366,260.704951 217.370091,254.220034 212.983093,237.93167 C209.908658,226.516685 208.870828,218.179476 208.826484,204.259903 L208.825284,202.840608 C208.836884,194.672214 209.157933,184.633261 209.605114,171.185381 C210.376069,148.00078 213.79261,132.71409 216.334239,121.332289 C218.054209,113.629996 219.354132,107.626433 219.354132,102.212372 C219.354132,100.105514 219.634597,97.1568247 219.926173,94.0567601 L220.027967,92.9734861 C220.416501,88.8241101 220.77388,84.5552796 220.633396,81.5249303 C220.563268,80.0122213 220.36004,78.7458615 220.056532,77.8111784 C219.39849,75.7846738 218.218924,74.7926623 217.050886,74.319003 C213.016784,72.6831053 207.083752,73.8938983 200.767445,77.2643023 C193.5468,81.1172643 185.881323,87.4227388 181.226749,92.1251087 C170.078149,103.388189 168.197052,106.181552 163.449564,130.566909 C160.514746,145.641534 157.152557,190.083423 153.408527,263.882996 C148.310625,260.529506 144.573436,256.539474 142.267189,251.849384 C137.44815,242.049164 135.781889,238.498147 133.16629,221.130117 C131.151349,207.750561 132.216961,189.426224 132.839043,178.568221 C133.052135,174.848508 133.207609,172.07036 133.207609,170.48586 C133.207609,164.09523 134.233106,147.312148 137.188741,122.72916 C137.780573,117.806695 138.265493,113.776123 138.700893,110.283341 L138.823994,109.299731 C139.331717,105.259782 139.777004,101.934213 140.256685,98.7255887 L140.372518,97.9574584 L140.582929,96.5951823 L140.761224,95.4724241 L140.885706,94.7044198 C141.871689,88.670391 143.122232,82.1576033 145.272592,71.2270532 C148.154429,56.5783156 150.225956,41.4023262 151.486676,25.701431 Z" id="font1-right" fill="#FFFFFF" />
|
||||
<path d="M78.8891291,0 L95.8005079,20.9095227 C95.225924,21.6575488 94.6661502,22.3687531 94.1213578,23.0610595 C90.498037,27.665481 87.5143717,31.5165865 85.0892155,38.8498924 C84.5933419,40.3493393 84.11666,41.7284904 83.6520528,43.0728622 C83.5490334,43.3709557 83.4494774,43.6590286 83.3486814,43.9513373 L82.9235478,45.1899741 L82.6412306,46.0224097 L82.2485912,47.2004158 C80.4111972,52.7806913 78.6427308,59.1891547 76.4859025,71.9475546 C76.3776982,72.5876213 76.2738377,73.2121994 76.1751238,73.8203757 L75.8128598,76.0522841 L78.072301,76.1393226 C78.6520627,76.1616563 79.233139,76.1970078 79.8150176,76.2458239 C87.4717734,76.8881795 94.6057156,79.8018442 100.240592,83.8134948 C106.031451,87.9361953 110.302115,93.214716 111.609957,98.4281539 C115.240663,112.901207 110.993666,140.365178 108.836316,154.571762 C108.454224,157.088603 108.185012,158.862829 107.988397,160.271632 C107.819607,161.481054 107.625793,162.940163 107.407149,164.586499 C106.781752,169.295591 105.954511,175.526376 104.92697,181.804864 L104.678362,183.301099 C104.604458,183.739061 104.529572,184.176727 104.455334,184.604273 L104.223432,185.919703 L103.986615,187.248058 C102.465647,195.80355 101.02459,204.149885 98.485251,205.777632 C97.1963754,206.603817 95.9047926,207.065865 94.5842529,207.065865 C93.8588313,207.065865 93.1344185,206.927653 92.4069507,206.668298 L95.4781875,150.606035 L95.4781875,125.416711 C95.4781875,119.629476 93.0062228,110.908957 89.011414,104.252932 C85.2823118,98.0396202 80.2711525,93.9905379 75.163077,93.8351964 C74.0775524,93.8021846 72.9925685,93.9378881 71.9187092,94.2290372 L71.4263054,96.8428337 C70.7159074,100.613041 70.0525722,104.126731 69.4322911,107.412363 C64.7908163,131.998276 62.5529774,143.865744 61.0463793,154.851795 L60.8656498,156.191994 L60.6074832,158.19028 L60.4564922,159.410154 C59.6660213,165.902037 59.0513782,172.654885 58.2694423,182.117243 L58.1071301,184.090317 C57.9422433,186.102896 57.7692971,188.236388 57.5853124,190.511952 C54.4936668,228.750117 54.5110376,253.296254 57.6025561,277.724448 C58.251829,282.854795 58.3254515,286.119184 57.7997112,287.772531 C57.3533443,287.365152 56.8839604,286.712284 56.3626176,285.917213 C52.9105561,280.652664 48.8648383,269.062761 47.655685,256.055841 C44.8625825,226.010303 44.1900887,198.199537 45.6450201,172.623459 C47.1003171,147.040956 50.0546274,122.362378 54.5097037,98.5879441 C54.6592145,97.7900827 54.8106671,96.9918965 54.9640617,96.1933855 C55.1162766,95.4010154 55.2701489,94.6096509 55.4255602,93.8194108 C54.5845527,93.7480795 53.7194585,93.7489156 52.8332622,93.823043 C51.80541,93.9090195 50.8219304,94.0875047 49.8871243,94.3559954 C40.9569857,96.920869 32.323789,109.590977 26.0163924,128.220937 C25.5897822,129.481002 25.1964216,130.603972 24.8064948,131.717231 C23.9716729,134.100687 23.1541733,136.435766 22.0577662,139.963149 C20.3672515,146.863794 19.2883814,155.11982 17.6274898,174.892165 L17.5002077,176.41617 C17.0934812,181.313351 16.6513406,186.891553 16.1571801,193.292133 C9.8071489,188.98619 5.71118886,185.065024 4.00517668,181.431253 C1.70360048,176.528943 0.414450227,167.507602 0,154.408561 C0.00301447963,88.3903589 8.23407782,59.6337727 27.7303891,30.3791899 L35.9962997,39.4225457 C36.9078334,45.6050425 36.6691333,52.0098284 36.334543,58.397272 L36.1828539,61.2074098 C35.9059422,66.2844755 35.6468393,71.3361913 35.8481016,76.2587175 L59.2444284,76.2587175 L59.8164199,73.1824272 C62.3280788,59.6740418 63.7105033,52.2383301 64.7073785,47.2643843 C65.3214048,44.2279628 65.7161407,42.4192098 66.1158122,40.7377245 L66.5998483,38.7653101 C67.0726403,36.911647 67.4709203,35.4207871 67.9619662,33.5825073 C70.1167026,25.5160341 74.7481339,10.4984271 78.8891291,0 Z" id="font1-left" fill="#FFFFFF" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.0 KiB |
3
.ncurc.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"upgrade": true
|
||||
}
|
8
.prettierignore
Normal file
@ -0,0 +1,8 @@
|
||||
dist
|
||||
.zeabur
|
||||
node_modules
|
||||
public/images
|
||||
|
||||
# The MDX files
|
||||
*.mdx
|
||||
*.md
|
20
.prettierrc
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"printWidth": 120,
|
||||
"bracketSpacing": true,
|
||||
"astroAllowShorthand": true,
|
||||
"astroOrganizeImportsMode": "All",
|
||||
"endOfLine": "lf",
|
||||
"plugins": ["prettier-plugin-astro", "prettier-plugin-organize-imports", "prettier-plugin-astro-organize-imports"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "**/*.astro",
|
||||
"options": {
|
||||
"parser": "astro"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
4
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"recommendations": ["astro-build.astro-vscode", "esbenp.prettier-vscode", "biomejs.Biome"],
|
||||
"unwantedRecommendations": []
|
||||
}
|
11
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "./node_modules/.bin/astro dev",
|
||||
"name": "Development server",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
163
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,163 @@
|
||||
{
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"quickfix.biome": "explicit"
|
||||
},
|
||||
"astro.content-intellisense": true,
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[astro]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"cSpell.words": [
|
||||
"alexinea",
|
||||
"alignfull",
|
||||
"alignleft",
|
||||
"alignright",
|
||||
"alignwide",
|
||||
"ameho",
|
||||
"amehochan",
|
||||
"aplayer",
|
||||
"artalk",
|
||||
"astro",
|
||||
"astrojs",
|
||||
"batang",
|
||||
"bigserial",
|
||||
"biomejs",
|
||||
"blogroll",
|
||||
"blogster",
|
||||
"blurhash",
|
||||
"bxaw",
|
||||
"captainofphb",
|
||||
"cfilter",
|
||||
"cimage",
|
||||
"ckenh",
|
||||
"cnip",
|
||||
"commentform",
|
||||
"csvg",
|
||||
"ctan",
|
||||
"cynosura",
|
||||
"datetime",
|
||||
"dichen",
|
||||
"dinesh",
|
||||
"dotum",
|
||||
"duoshuo",
|
||||
"emde",
|
||||
"eparams",
|
||||
"firis",
|
||||
"flexdinesh",
|
||||
"fmoran",
|
||||
"fong",
|
||||
"forencrypt",
|
||||
"giscus",
|
||||
"gogogo",
|
||||
"gotop",
|
||||
"gungseo",
|
||||
"hefei",
|
||||
"heiti",
|
||||
"honorbkk",
|
||||
"huaweiyal",
|
||||
"ianvs",
|
||||
"iconfont",
|
||||
"iroha",
|
||||
"isodate",
|
||||
"jamo",
|
||||
"jian",
|
||||
"jiasm",
|
||||
"jing",
|
||||
"jmoiron",
|
||||
"jungshik",
|
||||
"khalil",
|
||||
"khtml",
|
||||
"koanughi",
|
||||
"koaunghi",
|
||||
"lafoyer",
|
||||
"lanczos",
|
||||
"lantinghei",
|
||||
"lastmod",
|
||||
"lazyload",
|
||||
"linuxapi",
|
||||
"longluo",
|
||||
"loveness",
|
||||
"luoli",
|
||||
"luxon",
|
||||
"mboker",
|
||||
"microflash",
|
||||
"minagi",
|
||||
"miui",
|
||||
"mmwebid",
|
||||
"mmwebsdk",
|
||||
"mochi",
|
||||
"napi",
|
||||
"netease",
|
||||
"nextval",
|
||||
"nian",
|
||||
"nocolor",
|
||||
"nofollow",
|
||||
"nopd",
|
||||
"noto",
|
||||
"opendal",
|
||||
"oppo",
|
||||
"opposans",
|
||||
"pandiyan",
|
||||
"penheulim",
|
||||
"pilgi",
|
||||
"plaiceholder",
|
||||
"playform",
|
||||
"psql",
|
||||
"pwsz",
|
||||
"qrcode",
|
||||
"quan",
|
||||
"recma",
|
||||
"redmi",
|
||||
"regclass",
|
||||
"rehype",
|
||||
"rivo",
|
||||
"sauvignon",
|
||||
"sheng",
|
||||
"shiki",
|
||||
"shinmun",
|
||||
"shmily",
|
||||
"skrs",
|
||||
"sqlx",
|
||||
"syhily",
|
||||
"tabindex",
|
||||
"tagcloud",
|
||||
"taza",
|
||||
"teruteru",
|
||||
"timestamptz",
|
||||
"tlyric",
|
||||
"toolsmp",
|
||||
"tsconfigs",
|
||||
"tview",
|
||||
"ultrahtml",
|
||||
"unpic",
|
||||
"unsharp",
|
||||
"upyun",
|
||||
"urlset",
|
||||
"varchar",
|
||||
"velite",
|
||||
"vercel",
|
||||
"weapi",
|
||||
"wechat",
|
||||
"weibo",
|
||||
"xiao",
|
||||
"xinsenz",
|
||||
"xweb",
|
||||
"yefengs",
|
||||
"yetgul",
|
||||
"ying",
|
||||
"yuaanlin",
|
||||
"yual",
|
||||
"yufan",
|
||||
"yyjn",
|
||||
"zeabur",
|
||||
"zhihu"
|
||||
],
|
||||
"[mdx]": {
|
||||
"editor.defaultFormatter": "unifiedjs.vscode-mdx"
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
}
|
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Yufan Sheng
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
246
README.md
Normal file
@ -0,0 +1,246 @@
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="public/blog-poster-dark.png">
|
||||
<img alt="Yufan Blog Logo" src="public/blog-poster.png">
|
||||
</picture>
|
||||
|
||||
# Yufan Personal Weblog
|
||||
|
||||
This is a personal weblog for [Yufan Sheng](https://github.com/syhily)
|
||||
which is built on [Astro](https://astro.build) and hosted on [zeabur](https://zeabur.com).
|
||||
|
||||
[![Deployed on Zeabur](https://zeabur.com/deployed-on-zeabur-dark.svg)](https://zeabur.com?referralCode=syhily&utm_source=syhily)
|
||||
|
||||
## History
|
||||
|
||||
The blog's source code has evolved through four stages. Initially, it was built on WordPress in 2011.
|
||||
In 2017, I switched to Hexo and converted all my blog posts to Markdown;
|
||||
the code is available in the [Hexo branch](https://github.com/syhily/yufan.me/tree/hexo).
|
||||
By 2024, the blog had been rewritten using Next.js with App Router;
|
||||
you can find this version in the [Next branch](https://github.com/syhily/yufan.me/tree/next).
|
||||
Currently, the blog has transitioned to Astro, which is located in
|
||||
the [Astro branch](https://github.com/syhily/yufan.me/tree/astro).
|
||||
|
||||
## Core Frameworks
|
||||
|
||||
- [Node.js](https://nodejs.org): The latest Node.js LTS
|
||||
- [Astro](https://astro.build): Core engine
|
||||
- [Artalk](https://artalk.js.org): The self-hosted comment system
|
||||
- [Fuse.js](https://www.fusejs.io): Search engine
|
||||
- [Postgres](https://zeabur.com/docs/marketplace/postgresql): The view counter and like button for all my posts
|
||||
|
||||
## Local Development
|
||||
|
||||
You can fork and clone this project for your own use. But do so at your own risk.
|
||||
|
||||
The project uses npm for development. Run it locally with these commands:
|
||||
|
||||
```shell
|
||||
# Install the dependencies by using bun.
|
||||
npm install
|
||||
|
||||
# Init git hooks.
|
||||
npx husky
|
||||
|
||||
# Check the newer dependencies.
|
||||
npm update
|
||||
|
||||
# Start local development with a live preview. The weblog is hosted on http://localhost:4321
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Postgres Database
|
||||
|
||||
This blog uses Postgres to store post views and favorites. For security reasons,
|
||||
the configuration isn't defined in the `.env` file.
|
||||
Modify the `.env.example` file and rename it to `.env` for local development.
|
||||
|
||||
You can create a Postgres database by installing [Postgres.app](https://postgresapp.com).
|
||||
The default username is `your system username`, with no password.
|
||||
|
||||
Create and initialize the database and user with these commands:
|
||||
|
||||
```postgresql
|
||||
-- Create a database.
|
||||
CREATE DATABASE <db>;
|
||||
|
||||
-- Create a user.
|
||||
CREATE USER <db_user> PASSWORD '<strong_password>';
|
||||
|
||||
-- Grant the connection.
|
||||
GRANT CONNECT ON DATABASE <db> TO <db_user>;
|
||||
|
||||
-- Grant the database privilege.
|
||||
GRANT ALL PRIVILEGES ON DATABASE <db> TO <db_user>;
|
||||
|
||||
-- If you are using Postgres 15 or above.
|
||||
-- Switch to the created database and execute SQL.
|
||||
GRANT ALL ON SCHEMA public TO <db_user>;
|
||||
```
|
||||
|
||||
Most tables are created by the Artalk. [Execute the Artalk](https://artalk.js.org/guide/deploy.html) to create the
|
||||
tables.
|
||||
|
||||
The like table should be created manually. Execute the SQL below.
|
||||
|
||||
```postgresql
|
||||
-- Sequence and defined type
|
||||
CREATE SEQUENCE IF NOT EXISTS atk_likes_id_seq;
|
||||
|
||||
-- Table Definition
|
||||
CREATE TABLE "public"."atk_likes"
|
||||
(
|
||||
"id" int8 NOT NULL DEFAULT nextval('atk_likes_id_seq'::regclass),
|
||||
"created_at" timestamptz,
|
||||
"updated_at" timestamptz,
|
||||
"deleted_at" timestamptz,
|
||||
"token" varchar(255),
|
||||
"page_key" varchar(255),
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- Create table index
|
||||
CREATE INDEX IF NOT EXISTS "idx_atk_likes_token" ON "public"."atk_likes" ("token");
|
||||
```
|
||||
|
||||
### Comments Integration
|
||||
|
||||
This weblog uses artalk as its backend comment service. But since artalk didn't provide the latest comments API.
|
||||
We decide to query it directly from the Postgres database. So the comments and fav clicks are living in the same
|
||||
database.
|
||||
|
||||
### S3 Compatible Storage Integration
|
||||
|
||||
This blog will upload all the built resources at build stage. You can remove this feature by removing the
|
||||
`uploader` integration in `astro.config.ts`.
|
||||
|
||||
## Writing
|
||||
|
||||
All the posts should be placed in `src/content/posts` directory with MDX format.
|
||||
All the pages should be placed in `src/content/pages` directory with MDX format.
|
||||
You can add any scripts or other customizable features by leveraging the MDX.
|
||||
|
||||
### Front Matter
|
||||
|
||||
Front-matter is a block of YAML at the beginning of the file that is used to configure settings for your writings.
|
||||
Front-matter is terminated by three dashes when written in YAML.
|
||||
|
||||
```yaml
|
||||
---
|
||||
title: Hello World
|
||||
date: 2013/7/13 20:46:25
|
||||
---
|
||||
```
|
||||
|
||||
### Post Front Matter Settings
|
||||
|
||||
| Setting | Description | Required | Default |
|
||||
|-------------|--------------------------------------|----------|----------------------|
|
||||
| `slug` | ID (unique), used as the permalink | true | Filename |
|
||||
| `title` | Title | true | Filename |
|
||||
| `date` | Published date | true | |
|
||||
| `updated` | Updated date | false | Published date |
|
||||
| `comments` | Enables comment feature for the post | false | `true` |
|
||||
| `tags` | Tags | false | `null` |
|
||||
| `category` | Category | true | `null` |
|
||||
| `summary` | Post summary in plain text | false | First 140 characters |
|
||||
| `cover` | The cover image | false | `null` |
|
||||
| `published` | Whether the post should be published | false | `true` |
|
||||
| `toc` | Display the Table of Contents | false | `false` |
|
||||
| `alias` | The alternatives slugs for post | false | `[]` |
|
||||
|
||||
### Pages Front Matter Settings
|
||||
|
||||
| Setting | Description | Required | Default |
|
||||
|-------------|--------------------------------------|----------|----------------|
|
||||
| `slug` | ID (unique), used as the permalink | true | Filename |
|
||||
| `title` | Title | true | Filename |
|
||||
| `date` | Published date | true | |
|
||||
| `updated` | Updated date | false | Published date |
|
||||
| `comments` | Enables comment feature for the post | false | `true` |
|
||||
| `cover` | The cover image | false | `null` |
|
||||
| `published` | Whether the post should be published | false | `true` |
|
||||
| `toc` | Display the Table of Contents | false | `false` |
|
||||
|
||||
## Weblog Design
|
||||
|
||||
Almost all the design resources are placed in the file [yufan.me.sketch](docs/yufan.me.sketch).
|
||||
I mainly use the [Sketch](https://www.sketch.com) as my design tools.
|
||||
|
||||
The favicon is almost the same as the weblog logo. The main different is that we simplify the elements used in logo.
|
||||
Pick up the main park from the logo and change the dot color for readability in small icon.
|
||||
The background color is included in the exported favicon.
|
||||
That is because we want to make sure it could be viewed clearly in any browser.
|
||||
|
||||
The size of the favicon is following this
|
||||
[tutorial](https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs)
|
||||
to get it worked everywhere.
|
||||
|
||||
## Deploy the Weblog
|
||||
|
||||
This weblog is deployed on the [zeabur](https://zeabur.com) platform.
|
||||
You can check their documents and get your own weblog to be published without any budget at first.
|
||||
|
||||
Or you can host on your own machine. Use [Dockerfile](./Dockerfile) to build an image and run it locally.
|
||||
|
||||
The comment system is leverage the [Artalk](https://artalk.js.org), a self-hosted comment system.
|
||||
You should host it on your own machine.
|
||||
|
||||
## Short-Term TODO Checklist
|
||||
|
||||
- [ ] Add last modified time component for post.
|
||||
- [ ] Add light box for images and album component.
|
||||
- [ ] Check article grammar errors by using ChatGPT. Remain **42** posts.
|
||||
- [ ] Add music to the articles. Remain **42** posts.
|
||||
|
||||
## Long-Term TODO Checklist
|
||||
|
||||
- [ ] Use self-developed comment solution.
|
||||
- [ ] Support modification after commenting in 60 minutes even if you have refreshed the page.
|
||||
- [ ] Support login into the blog for managing the comments.
|
||||
- [ ] Slide share components integration.
|
||||
- [ ] Add han.js support for better typography.
|
||||
- [ ] Drop bootstrap, in favor of tailwind css.
|
||||
|
||||
## License
|
||||
|
||||
The source code of this blog is licensed under the [MIT](LICENSE) license,
|
||||
feel to free to use it without any legal risks.
|
||||
|
||||
The [content](src/content) of this blog's posts is licensed under the
|
||||
[CC BY-NC-SA 4.0](src/content/LICENSE) license.
|
||||
|
||||
### Logo Fonts License
|
||||
|
||||
The fonts used in weblog logo is [M+A1](https://booth.pm/ja/items/2347968) with [license](licenses/LICENSE.m-plus.txt),
|
||||
[UnGungseo](https://kldp.net/unfonts) with [license](licenses/LICENSE.un-fonts.txt),
|
||||
and [Iroha Mochi](https://modi.jpn.org/font_iroha-mochi.php) with [license](licenses/LICENSE.iroha-mochi.txt).
|
||||
|
||||
They are the fonts that can be used in business without any charge.
|
||||
|
||||
### Open Graph Font & Web Font License
|
||||
|
||||
The [OPPOSans 4.0](https://open.oppomobile.com/new/developmentDoc/info?id=13223)
|
||||
is used for rendering the open graph image in my weblog.
|
||||
We also use it as the main web font for articles.
|
||||
It can be used in business scenarios without any modification.
|
||||
The license file is [here](licenses/LICENSE.opposans.txt)
|
||||
|
||||
### Third Party Codes License
|
||||
|
||||
Some codes in this project are copied from other projects. I have added the comments in the files' header.
|
||||
|
||||
The source codes used from third party projects are:
|
||||
|
||||
- [seo.ts](src/helpers/seo.ts)
|
||||
from [flexdinesh/blogster](https://github.com/flexdinesh/blogster/blob/main/packages/shared/src/seo.ts)
|
||||
with [license](licenses/LICENSE.flexdinesh.txt)
|
||||
- [og.ts](src/helpers/og.ts)
|
||||
from [yuaanlin/yual.in](https://github.com/yuaanlin/yual.in/blob/main/pages/og_image/%5Bslug%5D.tsx)
|
||||
with [permission](licenses/LICENSE.yuaanlin.jpg)
|
||||
- [images.ts](src/helpers/images.ts)
|
||||
and [config.ts](src/content/config.ts)
|
||||
from [zce/velite](https://github.com/zce/velite/blob/main/src/assets.ts)
|
||||
with [license](licenses/LICENSE.zce.txt)
|
||||
- [images.ts](src/helpers/images.ts)
|
||||
from [vercel/next.js](https://github.com/vercel/next.js/blob/canary/packages/next/src/shared/lib/image-blur-svg.ts)
|
||||
with [license](licenses/LICENSE.vercel.txt)
|
80
astro.config.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import mdx from '@astrojs/mdx';
|
||||
import zeabur from '@zeabur/astro-adapter/serverless';
|
||||
import { uploader } from 'astro-uploader';
|
||||
import { defineConfig, envField } from 'astro/config';
|
||||
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
|
||||
import rehypeExternalLinks from 'rehype-external-links';
|
||||
import rehypeSlug from 'rehype-slug';
|
||||
import options from './options';
|
||||
import { astroImage } from './plugins/images';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// This will override the import.meta.env.SITE. No need to introduce method.
|
||||
site: options.isProd() ? options.website : options.local.website,
|
||||
output: 'server',
|
||||
security: {
|
||||
checkOrigin: true,
|
||||
},
|
||||
image: {
|
||||
domains: ['localhost', '127.0.0.1'],
|
||||
service: !options.isProd() ? { entrypoint: './plugins/resize', config: {} } : undefined,
|
||||
},
|
||||
experimental: {
|
||||
contentLayer: true,
|
||||
contentIntellisense: true,
|
||||
env: {
|
||||
schema: {
|
||||
// Postgres Database
|
||||
POSTGRES_HOST: envField.string({ context: 'server', access: 'secret' }),
|
||||
POSTGRES_PORT: envField.number({ context: 'server', access: 'secret' }),
|
||||
POSTGRES_USERNAME: envField.string({ context: 'server', access: 'secret' }),
|
||||
POSTGRES_PASSWORD: envField.string({ context: 'server', access: 'secret' }),
|
||||
POSTGRES_DATABASE: envField.string({ context: 'server', access: 'secret' }),
|
||||
// Artalk Comment
|
||||
ARTALK_HOST: envField.string({ context: 'server', access: 'secret' }),
|
||||
},
|
||||
validateSecrets: true,
|
||||
},
|
||||
},
|
||||
integrations: [
|
||||
mdx({
|
||||
remarkPlugins: [astroImage],
|
||||
rehypePlugins: [
|
||||
[rehypeExternalLinks, { rel: 'nofollow', target: '_blank' }],
|
||||
rehypeSlug,
|
||||
[rehypeAutolinkHeadings, { behavior: 'append', properties: {} }],
|
||||
],
|
||||
}),
|
||||
uploader({
|
||||
paths: ['images', 'og', 'cats'],
|
||||
endpoint: process.env.S3_ENDPOINT,
|
||||
bucket: process.env.S3_BUCKET as string,
|
||||
accessKey: process.env.S3_ACCESS_KEY as string,
|
||||
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY as string,
|
||||
}),
|
||||
],
|
||||
adapter: zeabur(),
|
||||
markdown: {
|
||||
gfm: true,
|
||||
shikiConfig: {
|
||||
theme: 'solarized-light',
|
||||
wrap: false,
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: options.local.port,
|
||||
},
|
||||
devToolbar: {
|
||||
// I don't need such toolbar.
|
||||
enabled: false,
|
||||
},
|
||||
vite: {
|
||||
// Add this for avoiding the needless import optimize in Vite.
|
||||
optimizeDeps: { exclude: ['@napi-rs/canvas', 'opendal'] },
|
||||
},
|
||||
build: {
|
||||
assets: 'cats',
|
||||
assetsPrefix: options.assetsPrefix(),
|
||||
},
|
||||
});
|
23
biome.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.9.0/schema.json",
|
||||
"formatter": {
|
||||
"enabled": false
|
||||
},
|
||||
"organizeImports": {
|
||||
"enabled": false
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
"a11y": {
|
||||
"useGenericFontNames": "off"
|
||||
}
|
||||
}
|
||||
},
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true
|
||||
}
|
||||
}
|
18
docs/Dockerfile
Normal file
@ -0,0 +1,18 @@
|
||||
FROM node:lts AS base
|
||||
WORKDIR /app
|
||||
COPY package.json package-lock.json ./
|
||||
|
||||
FROM base AS build
|
||||
COPY . .
|
||||
|
||||
ENV ASTRO_TELEMETRY_DISABLED=1
|
||||
RUN NODE_ENV=development npm install
|
||||
RUN NODE_ENV=production npm run build
|
||||
|
||||
FROM base AS runtime
|
||||
RUN npm install --omit=dev
|
||||
COPY --from=build /app/dist ./dist
|
||||
ENV HOST=0.0.0.0
|
||||
ENV PORT=4321
|
||||
EXPOSE 4321
|
||||
CMD NODE_ENV=production node ./dist/server/entry.mjs
|
BIN
docs/yufan.me.sketch
Normal file
21
licenses/LICENSE.flexdinesh.txt
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Dinesh Pandiyan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
64
licenses/LICENSE.iroha-mochi.txt
Normal file
@ -0,0 +1,64 @@
|
||||
いろはモチ ver.1.00
|
||||
OpenType形式
|
||||
|
||||
公開日 2018.01.12
|
||||
MODI工場/倒神神倒
|
||||
|
||||
紹介・詳細ページ
|
||||
http://modi.jpn.org/font_iroha-mochi.php
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
懐かしい絵本みたいなひらがなフォントです。
|
||||
|
||||
ウェイト(太さ)は1種類のみです。
|
||||
|
||||
----------------------------------------------
|
||||
## 仕様・収録文字について
|
||||
|
||||
−ひらがな・カタカナ
|
||||
−illustratorやInDesignの合成フォント機能における「かな」に含まれる全文字です。
|
||||
−おまけでいくつか基本的な約物(記号)
|
||||
|
||||
ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんゝゞ
|
||||
ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶーヽヾ
|
||||
濁点付きの『う』
|
||||
小書きの『か』
|
||||
小書きの『け』
|
||||
濁点付きの『ワ』
|
||||
濁点付きの『ヰ』
|
||||
濁点付きの『ヱ』
|
||||
濁点付きの『ヲ』
|
||||
"',{}、。,.・:;?!゛゜´`¨^ ̄_〆ー—‐/〜|…‥‘’“”()〔〕[]{}〈〉《》「」『』【】′″
|
||||
|
||||
----------------------------------------------
|
||||
## ライセンスについて
|
||||
|
||||
−「いろはモチ」は、MODI工場独自ライセンスです。
|
||||
|
||||
−連絡表記不要。商用、非商用問わずご自由にどうぞ。素材集書籍などへの収録も同様です。
|
||||
|
||||
−通常利用、商用利用、改変、再配布、埋め込みもOK。とにかくご自由にどうぞ。
|
||||
|
||||
−オリジナル・改造フォントともに、フォント単体で有料販売してはいけません。
|
||||
|
||||
----------------------------------------------
|
||||
## 免責事項
|
||||
|
||||
このフォントの使用に関してはすべて無保証とさせていただきます。
|
||||
|
||||
----------------------------------------------
|
||||
## 更新履歴
|
||||
|
||||
■2018.01.12 v1.00
|
||||
公開
|
||||
|
||||
----------------------------------------------
|
||||
## MODI工場ホームページ
|
||||
http://modi.jpn.org/
|
||||
|
||||
## 連絡先
|
||||
modi@modi.jpn.org
|
||||
|
||||
誤字などのミスがあったら教えていただければ幸いです。
|
||||
お返事はできないですがご了承ください。
|
10
licenses/LICENSE.m-plus.txt
Normal file
@ -0,0 +1,10 @@
|
||||
M+ FONTS Copyright (C) 2002-2019 M+ FONTS PROJECT
|
||||
|
||||
-
|
||||
|
||||
These fonts are free software.
|
||||
Unlimited permission is granted to use, copy, and distribute them, with
|
||||
or without modification, either commercially or noncommercially.
|
||||
THESE FONTS ARE PROVIDED "AS IS" WITHOUT WARRANTY.
|
||||
|
||||
http://mplus-fonts.osdn.jp
|
34
licenses/LICENSE.opposans.txt
Normal file
@ -0,0 +1,34 @@
|
||||
License Notice
|
||||
Copyright 2024 Guangdong OPPO Mobile Telecommunications Corp., Ltd.
|
||||
|
||||
OPPO Sans Fonts Software is licensed under OPPO Sans Fonts License Agreement.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
OPPO Sans Fonts License Agreement
|
||||
|
||||
THIS OPPO SANS FONTS LICENSE AGREEMENT ("AGREEMENT") IS A LEGAL AGREEMENT BETWEEN YOU (EITHER A SINGLE INDIVIDUAL, OR SINGLE LEGAL ENTITY) AND GUANGDONG OPPO MOBILE TELECOMMUNICATION CORP.,LTD. ( "LICENSOR") FOR THE USE OF THE OPPO SANS FONTS ACCOMPANYING THIS AGREEMENT. BY DOWNLOADING, COPYING OR OTHERWISE USING OPPO SANS FONTS YOU INDICATE THAT YOU AGREE TO BE BOUND BY ALL OF THE TERMS OF THIS AGREEMENT. IF YOU DO NOT AGREE TO THE TERMS OF THIS AGREEMENT, YOU MAY NOT DOWNLOAD, COPY OR OTHERWISE USE THE OPPO SANS FONTS, AND YOU SHALL PROMPTLY DESTROY AND DELETE ALL THE OPPO SANS FONTS.
|
||||
|
||||
1.Definition
|
||||
"OPPO Sans Fonts" shall mean the collection of fonts software components provided by Licensor under this Agreement and clearly marked as "OPPO Sans".
|
||||
|
||||
"YOU" shall mean an individual or legal entity exercising permissions granted by this Agreement.
|
||||
|
||||
2.GRANT OF LICENSE
|
||||
|
||||
Subject to the terms and conditions of this Agreement, Licensor hereby grant YOU a non-transferable, non-exclusive, royalty-free, revocable, worldwide copyright license to use, copy, merge, embed, bundle, redistribute and/or sell unmodified copies of OPPO Sans Fonts with any software except for fonts software,subject to the following conditions:
|
||||
1)YOU shall make a prominent notice in the software to state that OPPO Sans Fonts are used.
|
||||
2)YOU may not make any modifications to OPPO Sans Fonts or any of their individual components.
|
||||
3)Neither OPPO Sans Fonts nor any of their individual components may be redistributed or sold in a stand-alone base. This limitation does not apply to any work created by using OPPO Sans Fonts. You can freely distribute or sell your work, such as materials, logos, application software etc. created by using OPPO Sans Fonts.
|
||||
4)YOU shall retain the copyright notice and this Agreement in any copies of OPPO Sans Fonts.
|
||||
|
||||
3.Termination
|
||||
This Agreement will be automatically terminated if YOU breach any of this Agreement.
|
||||
|
||||
4.NO WARRANTY
|
||||
YOU AGREE THAT THE OPPO SANS FONTS ARE PROVIDED BY LICENSOR ON AN "AS IS" BASIS. LICENSOR MAKES NO WARRANTY, EXPRESSED OR IMPLIED OR STATUTORY, WITH RESPECT TO ANY OF THE OPPO SANS FONTS, INCLUDING WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.
|
||||
|
||||
5.NO LIABILITY
|
||||
|
||||
IN NO EVENT SHALL LICENSOR BE LIABLE FOR ANY DIRECT OR INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE OF OR INABILITY TO USE OPPO SANS FONTS, WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHER LEGAL THEORY, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
YOU EXPRESSLY ASSUME ALL LIABILITIES AND RISKS FOR USE OF OPPO SANS FONTS. SHOULD THE OPPO SANS FONTS PROVE DEFECTIVE, YOU ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
37
licenses/LICENSE.un-fonts.txt
Normal file
@ -0,0 +1,37 @@
|
||||
Copyright (c) 1998-2004 Koanughi Un.
|
||||
|
||||
Please see the enclosed file COPYING for license information (GPL). If you
|
||||
did not receive this file, see http://www.gnu.org/licenses/gpl.txt.
|
||||
|
||||
|
||||
Un-fonts is comes from the HLaTeX as type1 fonts in 1998 by Koaunghi Un,
|
||||
he made type1 fonts to use with Korean TeX(HLaTeX [1]) in the late 1990's and
|
||||
release it under the GNU GPL license.
|
||||
|
||||
It converted to TrueType with the FontForge(PfaEdit) by Won-kyu Park in 2003.
|
||||
|
||||
|
||||
Core families (9 fonts)
|
||||
* UnBatang, UnBatangBold: serif
|
||||
* UnDotum, UnDotumBold: sans-serif
|
||||
* UnGraphic, UnGraphicBold: sans-serif style
|
||||
* UnPilgi, UnPilgiBold: script
|
||||
* UnGungseo: cursive, brush-stroke
|
||||
|
||||
Extra families (10 fonts)
|
||||
* UnPen, UnPenheulim: script
|
||||
* UnTaza: typewriter style
|
||||
* UnBom: decorative
|
||||
* UnShinmun
|
||||
* UnYetgul: old Korean printing style
|
||||
* UnJamoSora, UnJamoNovel, UnJamoDotum, UnJamoBatang
|
||||
|
||||
Please send problems and feedback at http://kldp.net/projects/unfonts/
|
||||
|
||||
|
||||
Project maintainers:
|
||||
|
||||
* Won-kyu Park <wkpark@kldp.org>
|
||||
* Jungshik Shin <jshin@mailaps.org>
|
||||
----
|
||||
[1] http://ftp.dante.de/tex-archive/fonts/korean/HLaTeX and other CTAN archives)
|
21
licenses/LICENSE.vercel.txt
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2024 Vercel, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
BIN
licenses/LICENSE.yuaanlin.jpg
Normal file
After Width: | Height: | Size: 88 KiB |
21
licenses/LICENSE.zce.txt
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2024 zce <w@zce.me> (https://zce.me)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
221
options.ts
Normal file
@ -0,0 +1,221 @@
|
||||
import { z } from 'astro/zod';
|
||||
|
||||
const isProd = (): boolean => import.meta.env.MODE === 'production' || process.env.NODE_ENV === 'production';
|
||||
|
||||
// The type of the options, use zod for better validation.
|
||||
const Options = z
|
||||
.object({
|
||||
local: z
|
||||
.object({
|
||||
port: z.number(),
|
||||
})
|
||||
.transform((local) => ({ ...local, website: `http://localhost:${local.port}` })),
|
||||
title: z.string().max(40),
|
||||
website: z
|
||||
.string()
|
||||
.url()
|
||||
.refine((u) => !u.endsWith('/'))
|
||||
.readonly(),
|
||||
description: z.string().max(100),
|
||||
keywords: z.array(z.string()),
|
||||
author: z.object({ name: z.string(), email: z.string().email(), url: z.string().url() }),
|
||||
navigation: z.array(z.object({ text: z.string().trim(), link: z.string(), target: z.string().optional() })),
|
||||
socials: z.array(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
icon: z.string(),
|
||||
type: z.enum(['link', 'qrcode']),
|
||||
title: z.string().optional(),
|
||||
link: z.string().url(),
|
||||
}),
|
||||
),
|
||||
settings: z.object({
|
||||
footer: z.object({
|
||||
initialYear: z.number().max(2024),
|
||||
icpNo: z.string().optional(),
|
||||
moeIcpNo: z.string().optional(),
|
||||
astroBadge: z.boolean().default(true),
|
||||
}),
|
||||
locale: z.string().optional().default('zh-CN'),
|
||||
timeZone: z.string().optional().default('Asia/Shanghai'),
|
||||
timeFormat: z.string().optional().default('yyyy-MM-dd HH:mm:ss'),
|
||||
twitter: z.string(),
|
||||
assetPrefix: z
|
||||
.string()
|
||||
.url()
|
||||
.refine((u) => !u.endsWith('/'))
|
||||
.readonly(),
|
||||
post: z.object({
|
||||
sort: z.enum(['asc', 'desc']),
|
||||
feature: z.array(z.string()).min(3).optional(),
|
||||
category: z.array(z.string()).optional(),
|
||||
}),
|
||||
pagination: z.object({
|
||||
posts: z.number().optional().default(5),
|
||||
category: z.number().optional().default(7),
|
||||
tags: z.number().optional().default(7),
|
||||
search: z.number().optional().default(7),
|
||||
}),
|
||||
feed: z.object({
|
||||
full: z.boolean().optional().default(true),
|
||||
size: z.number().optional().default(20),
|
||||
}),
|
||||
sidebar: z.object({
|
||||
search: z.boolean().default(false),
|
||||
post: z.number().default(6),
|
||||
comment: z.number().default(0),
|
||||
tag: z.number().default(20),
|
||||
}),
|
||||
comments: z.object({
|
||||
server: z.string().url().readonly(),
|
||||
size: z.number().default(10).readonly(),
|
||||
avatar: z.object({
|
||||
mirror: z.string().url().readonly(),
|
||||
size: z.number(),
|
||||
}),
|
||||
}),
|
||||
toc: z.object({
|
||||
minHeadingLevel: z.number().optional().default(2),
|
||||
maxHeadingLevel: z.number().optional().default(3),
|
||||
}),
|
||||
}),
|
||||
thumbnail: z
|
||||
.function()
|
||||
.args(z.object({ src: z.string().min(1), width: z.number().or(z.string()), height: z.number().or(z.string()) }))
|
||||
.returns(z.string()),
|
||||
})
|
||||
.transform((opts) => {
|
||||
const assetsPrefix = (): string => (isProd() ? opts.settings.assetPrefix : opts.local.website);
|
||||
return {
|
||||
...opts,
|
||||
// Monkey patch for the issue https://github.com/withastro/astro/issues/11282
|
||||
// No need to fallback to the import.meta.env.PROD I think.
|
||||
isProd,
|
||||
// Given that the import.meta.env.ASSETS_PREFIX has two types.
|
||||
// I have to use this uniform method instead.
|
||||
assetsPrefix,
|
||||
defaultOpenGraph: (): string => `${assetsPrefix()}/images/open-graph.png`,
|
||||
};
|
||||
})
|
||||
.refine(
|
||||
(options) => options.settings.toc.minHeadingLevel <= options.settings.toc.maxHeadingLevel,
|
||||
'Invalid toc setting, the minHeadingLevel should bellow the maxHeadingLevel',
|
||||
);
|
||||
|
||||
const options: z.input<typeof Options> = {
|
||||
local: {
|
||||
port: 4321,
|
||||
},
|
||||
title: '且听书吟',
|
||||
website: 'https://yufan.me',
|
||||
description: '诗与梦想的远方',
|
||||
keywords: ['雨帆', '且听书吟', 'syhily', 'amehochan', 'yufan'],
|
||||
author: {
|
||||
name: '雨帆',
|
||||
email: 'syhily@gmail.com',
|
||||
url: 'https://yufan.me',
|
||||
},
|
||||
navigation: [
|
||||
{
|
||||
text: '首页',
|
||||
link: '/',
|
||||
},
|
||||
{
|
||||
text: '关于',
|
||||
link: '/about',
|
||||
},
|
||||
{
|
||||
text: '留言',
|
||||
link: '/guestbook',
|
||||
},
|
||||
{
|
||||
text: '友链',
|
||||
link: '/links',
|
||||
},
|
||||
{
|
||||
text: '笔记',
|
||||
link: 'https://note.yufan.me',
|
||||
target: '_blank',
|
||||
},
|
||||
],
|
||||
socials: [
|
||||
{
|
||||
name: 'GitHub',
|
||||
icon: 'icon-github-fill',
|
||||
type: 'link',
|
||||
link: 'https://github.com/syhily',
|
||||
},
|
||||
{
|
||||
name: '知乎',
|
||||
icon: 'icon-zhihu-square-fill',
|
||||
type: 'link',
|
||||
link: 'https://www.zhihu.com/people/syhily',
|
||||
},
|
||||
{
|
||||
name: '微信',
|
||||
icon: 'icon-wechat',
|
||||
type: 'qrcode',
|
||||
title: '扫码加我微信好友',
|
||||
link: 'https://u.wechat.com/EBpmuKmrVz4YVFnoCJdnruA',
|
||||
},
|
||||
],
|
||||
settings: {
|
||||
footer: {
|
||||
initialYear: 2011,
|
||||
icpNo: '皖ICP备2021002315号-2',
|
||||
moeIcpNo: '萌ICP备20200318号',
|
||||
astroBadge: true,
|
||||
},
|
||||
locale: 'zh-CN',
|
||||
timeZone: 'Asia/Shanghai',
|
||||
timeFormat: 'yyyy-MM-dd',
|
||||
twitter: 'amehochan',
|
||||
assetPrefix: 'https://cat.yufan.me',
|
||||
post: {
|
||||
sort: 'desc',
|
||||
category: ['article', 'think', 'gossip', 'coding'],
|
||||
},
|
||||
pagination: {
|
||||
posts: 5,
|
||||
category: 7,
|
||||
tags: 7,
|
||||
search: 7,
|
||||
},
|
||||
feed: {
|
||||
full: true,
|
||||
size: 10,
|
||||
},
|
||||
sidebar: {
|
||||
search: true,
|
||||
post: 6,
|
||||
comment: 6,
|
||||
tag: 20,
|
||||
},
|
||||
comments: {
|
||||
server: 'https://comment.yufan.me',
|
||||
size: 10,
|
||||
avatar: {
|
||||
mirror: 'https://weavatar.com/avatar',
|
||||
size: 120,
|
||||
},
|
||||
},
|
||||
toc: {
|
||||
minHeadingLevel: 2,
|
||||
maxHeadingLevel: 3,
|
||||
},
|
||||
},
|
||||
thumbnail: ({ src, width, height }) => {
|
||||
if (src.endsWith('.svg')) {
|
||||
return src;
|
||||
}
|
||||
if (isProd()) {
|
||||
// Add upyun thumbnail support.
|
||||
return `${src}!upyun520/both/${width}x${height}/format/webp/quality/100/unsharp/true/progressive/true`;
|
||||
}
|
||||
// See https://docs.astro.build/en/reference/image-service-reference/#local-services
|
||||
// Remember to add the localhost to you image service settings.
|
||||
return `http://localhost:4321/_image?href=${src}&w=${width}&h=${height}&f=webp&q=100`;
|
||||
},
|
||||
};
|
||||
|
||||
export default Options.parse(options);
|
9644
package-lock.json
generated
Normal file
88
package.json
Normal file
@ -0,0 +1,88 @@
|
||||
{
|
||||
"name": "yufan.me",
|
||||
"version": "3.0.0",
|
||||
"private": true,
|
||||
"description": "The personal blog for Yufan Sheng",
|
||||
"keywords": [
|
||||
"blog",
|
||||
"astro",
|
||||
"yufan",
|
||||
"ameho",
|
||||
"syhily"
|
||||
],
|
||||
"homepage": "https://yufan.me",
|
||||
"bugs": {
|
||||
"url": "https://github.com/syhily/yufan.me/issues",
|
||||
"email": "syhily@gmail.com"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/syhily/yufan.me.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
"name": "Yufan Sheng",
|
||||
"email": "syhily@gmail.com",
|
||||
"url": "https://yufan.me"
|
||||
},
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"astro": "astro",
|
||||
"build": "rimraf dist && rimraf .zeabur && astro check && astro build",
|
||||
"dev": "astro dev",
|
||||
"lint": "biome check --write . && prettier . --write",
|
||||
"prepare": "npx husky",
|
||||
"preview": "astro preview",
|
||||
"start": "astro dev"
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*": [
|
||||
"biome check --no-errors-on-unmatched --files-ignore-unknown=true",
|
||||
"prettier --write --ignore-unknown"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^3.1.9",
|
||||
"@astrojs/rss": "^4.0.9",
|
||||
"@zeabur/astro-adapter": "^1.0.6",
|
||||
"astro": "^4.16.12",
|
||||
"drizzle-orm": "^0.36.2",
|
||||
"fuse.js": "^7.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"luxon": "^3.5.0",
|
||||
"marked": "^15.0.0",
|
||||
"pg": "^8.13.1",
|
||||
"qrcode-svg": "^1.1.0",
|
||||
"ultrahtml": "^1.5.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/check": "^0.9.4",
|
||||
"@biomejs/biome": "^1.9.4",
|
||||
"@napi-rs/canvas": "^0.1.61",
|
||||
"@types/lodash": "^4.17.13",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/pg": "^8.11.10",
|
||||
"@types/qrcode-svg": "^1.1.5",
|
||||
"@types/unist": "^3.0.3",
|
||||
"aplayer": "^1.10.1",
|
||||
"astro-uploader": "^1.1.3",
|
||||
"bootstrap": "^5.3.3",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-astro": "^0.14.1",
|
||||
"prettier-plugin-astro-organize-imports": "^0.4.11",
|
||||
"prettier-plugin-organize-imports": "^4.1.0",
|
||||
"rehype-autolink-headings": "^7.1.0",
|
||||
"rehype-external-links": "^3.0.0",
|
||||
"rehype-slug": "^6.0.0",
|
||||
"resize-sensor": "^0.0.6",
|
||||
"rimraf": "^6.0.1",
|
||||
"sharp": "^0.33.5",
|
||||
"typescript": "^5.6.3",
|
||||
"unist-util-select": "^5.1.0"
|
||||
},
|
||||
"packageManager": "npm@10.9.0",
|
||||
"engines": {
|
||||
"node": "22.11.0"
|
||||
}
|
||||
}
|
59
plugins/images.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import type { Literal, Node, Parent } from 'unist';
|
||||
import { selectAll } from 'unist-util-select';
|
||||
import options from '../options';
|
||||
import { imageMetadata } from '../src/helpers/images';
|
||||
import { urlJoin } from '../src/helpers/tools';
|
||||
|
||||
type ImageNode = Parent & {
|
||||
url: string;
|
||||
alt: string;
|
||||
name: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
attributes: (Literal & { name: string })[];
|
||||
};
|
||||
|
||||
export const astroImage = () => {
|
||||
return async (tree: Node) => {
|
||||
// Find all the image node.
|
||||
const imageNodes = selectAll('image', tree)
|
||||
.map((node) => node as ImageNode)
|
||||
.filter((imageNode) => !imageNode.url.startsWith('http'))
|
||||
.map(transformAstroImage);
|
||||
|
||||
// Process image with blur metadata.
|
||||
await Promise.all(imageNodes);
|
||||
return tree;
|
||||
};
|
||||
};
|
||||
|
||||
const transformAstroImage = async (imageNode: ImageNode) => {
|
||||
imageNode.type = 'mdxJsxFlowElement';
|
||||
imageNode.name = 'Image';
|
||||
|
||||
try {
|
||||
const metadata = await imageMetadata(imageNode.url);
|
||||
if (metadata == null) {
|
||||
throw new Error(`Failed to get image metadata: ${imageNode.url}`);
|
||||
}
|
||||
|
||||
imageNode.attributes = [
|
||||
{ type: 'mdxJsxAttribute', name: 'alt', value: imageNode.alt },
|
||||
{ type: 'mdxJsxAttribute', name: 'src', value: metadata.src },
|
||||
{ type: 'mdxJsxAttribute', name: 'width', value: imageNode.width ?? metadata.width },
|
||||
{ type: 'mdxJsxAttribute', name: 'height', value: imageNode.height ?? metadata.height },
|
||||
{ type: 'mdxJsxAttribute', name: 'blurDataURL', value: metadata.blurDataURL },
|
||||
{ type: 'mdxJsxAttribute', name: 'blurWidth', value: metadata.blurWidth },
|
||||
{ type: 'mdxJsxAttribute', name: 'blurHeight', value: metadata.blurHeight },
|
||||
];
|
||||
} catch (error) {
|
||||
imageNode.attributes = [
|
||||
{ type: 'mdxJsxAttribute', name: 'alt', value: imageNode.alt },
|
||||
{
|
||||
type: 'mdxJsxAttribute',
|
||||
name: 'src',
|
||||
value: imageNode.url.startsWith('/') ? urlJoin(options.assetsPrefix(), imageNode.url) : imageNode.url,
|
||||
},
|
||||
];
|
||||
}
|
||||
};
|
91
plugins/resize.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import type { ImageOutputFormat, ImageQualityPreset, LocalImageService } from 'astro';
|
||||
import { baseService } from 'astro/assets';
|
||||
|
||||
const qualityTable: Record<ImageQualityPreset, number> = {
|
||||
low: 25,
|
||||
mid: 50,
|
||||
high: 80,
|
||||
max: 100,
|
||||
};
|
||||
|
||||
const parseQuality = (quality: string): string | number => {
|
||||
const result = Number.parseInt(quality);
|
||||
if (Number.isNaN(result)) {
|
||||
return quality;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
type BaseServiceTransform = {
|
||||
src: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
format: string;
|
||||
quality?: string | null;
|
||||
};
|
||||
|
||||
interface SharpImageServiceConfig {
|
||||
/**
|
||||
* The `limitInputPixels` option passed to Sharp. See https://sharp.pixelplumbing.com/api-constructor for more information
|
||||
*/
|
||||
limitInputPixels?: import('sharp').SharpOptions['limitInputPixels'];
|
||||
}
|
||||
|
||||
const imageService: LocalImageService<SharpImageServiceConfig> = {
|
||||
getURL: baseService.getURL,
|
||||
getSrcSet: baseService.getSrcSet,
|
||||
getHTMLAttributes: baseService.getHTMLAttributes,
|
||||
validateOptions: baseService.validateOptions,
|
||||
parseURL: baseService.parseURL,
|
||||
async transform(inputBuffer, transformOptions, config) {
|
||||
const { default: sharp } = await import('sharp');
|
||||
const transform: BaseServiceTransform = transformOptions as BaseServiceTransform;
|
||||
|
||||
// Sharp has some support for SVGs, we could probably support this once Sharp is the default and only service.
|
||||
if (transform.format === 'svg') return { data: inputBuffer, format: 'svg' };
|
||||
|
||||
const result = sharp(inputBuffer, {
|
||||
failOnError: false,
|
||||
pages: -1,
|
||||
limitInputPixels: config.service.config.limitInputPixels,
|
||||
});
|
||||
|
||||
result.rotate();
|
||||
|
||||
// Never resize using both width and height at the same time, prioritizing width.
|
||||
if (transform.height) {
|
||||
if (!transform.width) {
|
||||
result.resize({ height: Math.round(transform.height) });
|
||||
} else {
|
||||
// Allow the width and height to be set.
|
||||
result.resize({ width: Math.round(transform.width), height: Math.round(transform.height) });
|
||||
}
|
||||
} else if (transform.width) {
|
||||
result.resize({ width: Math.round(transform.width) });
|
||||
}
|
||||
|
||||
if (transform.format) {
|
||||
let quality: number | string | undefined = undefined;
|
||||
if (transform.quality) {
|
||||
const parsedQuality = parseQuality(transform.quality);
|
||||
if (typeof parsedQuality === 'number') {
|
||||
quality = parsedQuality;
|
||||
} else {
|
||||
quality = transform.quality in qualityTable ? qualityTable[transform.quality] : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
result.toFormat(transform.format as keyof import('sharp').FormatEnum, { quality: quality });
|
||||
}
|
||||
|
||||
const { data, info } = await result.toBuffer({ resolveWithObject: true });
|
||||
|
||||
return {
|
||||
data: data,
|
||||
format: info.format as ImageOutputFormat,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default imageService;
|
BIN
public/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
public/blog-poster-dark.png
Normal file
After Width: | Height: | Size: 103 KiB |
BIN
public/blog-poster.png
Normal file
After Width: | Height: | Size: 128 KiB |
BIN
public/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
12
public/favicon.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="300px" height="300px" viewBox="0 0 300 300" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>favicon</title>
|
||||
<g id="favicon" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<rect fill="#263148" x="0" y="0" width="300" height="300" />
|
||||
<g id="logo-white" transform="translate(9, 3.888)">
|
||||
<path d="M159,154.195523 C167.013592,152.617424 174.05936,152.751451 180.129673,154.674602 C190.120795,157.839913 194.348511,161.02564 199.517296,168.40144 C202.925628,173.265093 205.718707,181.861769 208,194.149433 C202.817237,195.503225 198.494331,195.463815 195.074572,193.809733 C188.963104,190.853715 183.30068,186.732689 175.022826,177.505654 C169.768056,171.648346 164.430736,163.875789 159,154.195523 Z" id="font1-dot" fill="#EEB4B4" />
|
||||
<path d="M151.486676,25.701431 C155.616373,28.5082875 160.109234,31.601356 164.965286,34.9806001 C165.393463,35.2785613 165.822641,35.5757097 166.255249,35.8738863 L167.105716,36.458366 C168.619019,37.4954138 170.108644,38.5008303 171.499238,39.4303971 L172.608374,40.1697969 C174.26724,41.2727003 175.735093,42.2354804 176.860606,42.9690389 L176.448028,45.1207071 L166.710146,84.6326462 C180.591569,66.4261557 193.885083,57.2272012 206.997372,58.6211808 C208.743695,58.806834 210.475625,59.0033727 212.18144,59.2464237 C212.733943,59.3251464 213.291751,59.4029337 213.853878,59.4813177 C215.158468,59.6632319 216.474026,59.8465926 217.787079,60.0508718 L218.661915,60.1902579 C225.09927,61.241972 231.826526,62.8614549 236.986443,68.0144332 C240.889249,71.9119921 243.813448,77.8014483 245.23642,86.708071 C247.095663,98.3453903 243.120654,117.723729 238.770002,139.330906 L238.580551,140.271866 C237.890376,143.700241 237.191343,147.180322 236.50179,150.693982 L236.044022,153.039529 C235.556986,155.549827 235.077075,158.073824 234.610494,160.607168 L234.263405,162.507565 L233.922672,164.406776 C228.900089,192.67064 226.130123,221.241925 234.44056,240.371255 C240.652266,254.669635 245.935235,262.932333 250.296038,267.670416 C253.412465,271.056463 256.180453,272.79959 258.553083,273.698031 C262.383549,275.148509 265.383302,274.528886 267.668585,273.982958 C268.14919,273.865733 268.422366,273.767797 268.665926,273.767797 C271.112421,273.767797 275.809409,272.387068 282.731388,269.370175 C283.375366,277.48654 282.878184,284.333295 281.156359,289.899262 C280.659157,291.506519 280.558961,292.472131 279.535062,293.024782 C275.748117,295.068793 270.498503,293.963559 265.488631,292.694915 C256.722323,290.485677 244.816282,287.548472 234.696635,275.178958 C233.697221,273.957347 232.737161,272.794212 231.813783,271.675534 C222.758366,260.704951 217.370091,254.220034 212.983093,237.93167 C209.908658,226.516685 208.870828,218.179476 208.826484,204.259903 L208.825284,202.840608 C208.836884,194.672214 209.157933,184.633261 209.605114,171.185381 C210.376069,148.00078 213.79261,132.71409 216.334239,121.332289 C218.054209,113.629996 219.354132,107.626433 219.354132,102.212372 C219.354132,100.105514 219.634597,97.1568247 219.926173,94.0567601 L220.027967,92.9734861 C220.416501,88.8241101 220.77388,84.5552796 220.633396,81.5249303 C220.563268,80.0122213 220.36004,78.7458615 220.056532,77.8111784 C219.39849,75.7846738 218.218924,74.7926623 217.050886,74.319003 C213.016784,72.6831053 207.083752,73.8938983 200.767445,77.2643023 C193.5468,81.1172643 185.881323,87.4227388 181.226749,92.1251087 C170.078149,103.388189 168.197052,106.181552 163.449564,130.566909 C160.514746,145.641534 157.152557,190.083423 153.408527,263.882996 C148.310625,260.529506 144.573436,256.539474 142.267189,251.849384 C137.44815,242.049164 135.781889,238.498147 133.16629,221.130117 C131.151349,207.750561 132.216961,189.426224 132.839043,178.568221 C133.052135,174.848508 133.207609,172.07036 133.207609,170.48586 C133.207609,164.09523 134.233106,147.312148 137.188741,122.72916 C137.780573,117.806695 138.265493,113.776123 138.700893,110.283341 L138.823994,109.299731 C139.331717,105.259782 139.777004,101.934213 140.256685,98.7255887 L140.372518,97.9574584 L140.582929,96.5951823 L140.761224,95.4724241 L140.885706,94.7044198 C141.871689,88.670391 143.122232,82.1576033 145.272592,71.2270532 C148.154429,56.5783156 150.225956,41.4023262 151.486676,25.701431 Z" id="font1-right" fill="#FFFFFF" />
|
||||
<path d="M78.8891291,0 L95.8005079,20.9095227 C95.225924,21.6575488 94.6661502,22.3687531 94.1213578,23.0610595 C90.498037,27.665481 87.5143717,31.5165865 85.0892155,38.8498924 C84.5933419,40.3493393 84.11666,41.7284904 83.6520528,43.0728622 C83.5490334,43.3709557 83.4494774,43.6590286 83.3486814,43.9513373 L82.9235478,45.1899741 L82.6412306,46.0224097 L82.2485912,47.2004158 C80.4111972,52.7806913 78.6427308,59.1891547 76.4859025,71.9475546 C76.3776982,72.5876213 76.2738377,73.2121994 76.1751238,73.8203757 L75.8128598,76.0522841 L78.072301,76.1393226 C78.6520627,76.1616563 79.233139,76.1970078 79.8150176,76.2458239 C87.4717734,76.8881795 94.6057156,79.8018442 100.240592,83.8134948 C106.031451,87.9361953 110.302115,93.214716 111.609957,98.4281539 C115.240663,112.901207 110.993666,140.365178 108.836316,154.571762 C108.454224,157.088603 108.185012,158.862829 107.988397,160.271632 C107.819607,161.481054 107.625793,162.940163 107.407149,164.586499 C106.781752,169.295591 105.954511,175.526376 104.92697,181.804864 L104.678362,183.301099 C104.604458,183.739061 104.529572,184.176727 104.455334,184.604273 L104.223432,185.919703 L103.986615,187.248058 C102.465647,195.80355 101.02459,204.149885 98.485251,205.777632 C97.1963754,206.603817 95.9047926,207.065865 94.5842529,207.065865 C93.8588313,207.065865 93.1344185,206.927653 92.4069507,206.668298 L95.4781875,150.606035 L95.4781875,125.416711 C95.4781875,119.629476 93.0062228,110.908957 89.011414,104.252932 C85.2823118,98.0396202 80.2711525,93.9905379 75.163077,93.8351964 C74.0775524,93.8021846 72.9925685,93.9378881 71.9187092,94.2290372 L71.4263054,96.8428337 C70.7159074,100.613041 70.0525722,104.126731 69.4322911,107.412363 C64.7908163,131.998276 62.5529774,143.865744 61.0463793,154.851795 L60.8656498,156.191994 L60.6074832,158.19028 L60.4564922,159.410154 C59.6660213,165.902037 59.0513782,172.654885 58.2694423,182.117243 L58.1071301,184.090317 C57.9422433,186.102896 57.7692971,188.236388 57.5853124,190.511952 C54.4936668,228.750117 54.5110376,253.296254 57.6025561,277.724448 C58.251829,282.854795 58.3254515,286.119184 57.7997112,287.772531 C57.3533443,287.365152 56.8839604,286.712284 56.3626176,285.917213 C52.9105561,280.652664 48.8648383,269.062761 47.655685,256.055841 C44.8625825,226.010303 44.1900887,198.199537 45.6450201,172.623459 C47.1003171,147.040956 50.0546274,122.362378 54.5097037,98.5879441 C54.6592145,97.7900827 54.8106671,96.9918965 54.9640617,96.1933855 C55.1162766,95.4010154 55.2701489,94.6096509 55.4255602,93.8194108 C54.5845527,93.7480795 53.7194585,93.7489156 52.8332622,93.823043 C51.80541,93.9090195 50.8219304,94.0875047 49.8871243,94.3559954 C40.9569857,96.920869 32.323789,109.590977 26.0163924,128.220937 C25.5897822,129.481002 25.1964216,130.603972 24.8064948,131.717231 C23.9716729,134.100687 23.1541733,136.435766 22.0577662,139.963149 C20.3672515,146.863794 19.2883814,155.11982 17.6274898,174.892165 L17.5002077,176.41617 C17.0934812,181.313351 16.6513406,186.891553 16.1571801,193.292133 C9.8071489,188.98619 5.71118886,185.065024 4.00517668,181.431253 C1.70360048,176.528943 0.414450227,167.507602 0,154.408561 C0.00301447963,88.3903589 8.23407782,59.6337727 27.7303891,30.3791899 L35.9962997,39.4225457 C36.9078334,45.6050425 36.6691333,52.0098284 36.334543,58.397272 L36.1828539,61.2074098 C35.9059422,66.2844755 35.6468393,71.3361913 35.8481016,76.2587175 L59.2444284,76.2587175 L59.8164199,73.1824272 C62.3280788,59.6740418 63.7105033,52.2383301 64.7073785,47.2643843 C65.3214048,44.2279628 65.7161407,42.4192098 66.1158122,40.7377245 L66.5998483,38.7653101 C67.0726403,36.911647 67.4709203,35.4207871 67.9619662,33.5825073 C70.1167026,25.5160341 74.7481339,10.4984271 78.8891291,0 Z" id="font1-left" fill="#FFFFFF" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.0 KiB |
68
public/feed.xsl
Normal file
BIN
public/icon-192.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
public/icon-512.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
public/images/2011/04/2011041420484000.jpg
Normal file
After Width: | Height: | Size: 425 KiB |
BIN
public/images/2011/04/2011041520510800.jpg
Normal file
After Width: | Height: | Size: 267 KiB |
BIN
public/images/2011/04/2011041520580200.jpg
Normal file
After Width: | Height: | Size: 357 KiB |
BIN
public/images/2011/04/2011041522562500.jpg
Normal file
After Width: | Height: | Size: 243 KiB |
BIN
public/images/2011/04/2011042321083500.jpg
Normal file
After Width: | Height: | Size: 435 KiB |
BIN
public/images/2011/04/2011042321142000.jpg
Normal file
After Width: | Height: | Size: 418 KiB |
BIN
public/images/2011/04/2011042321143500.jpg
Normal file
After Width: | Height: | Size: 268 KiB |
BIN
public/images/2011/04/2011042321155000.jpg
Normal file
After Width: | Height: | Size: 435 KiB |
BIN
public/images/2011/04/2011042511393900.jpg
Normal file
After Width: | Height: | Size: 191 KiB |
BIN
public/images/2011/04/2011042521290100.jpg
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
public/images/2011/04/2011042521292600.jpg
Normal file
After Width: | Height: | Size: 138 KiB |
BIN
public/images/2011/04/2011042521293200.jpg
Normal file
After Width: | Height: | Size: 122 KiB |
BIN
public/images/2011/04/2011042521302200.jpg
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
public/images/2011/04/2011042521302700.jpg
Normal file
After Width: | Height: | Size: 80 KiB |
BIN
public/images/2011/04/2011042521351900.jpg
Normal file
After Width: | Height: | Size: 178 KiB |
BIN
public/images/2011/04/2011042521393900.jpg
Normal file
After Width: | Height: | Size: 112 KiB |
BIN
public/images/2011/05/2011051421445100.jpg
Normal file
After Width: | Height: | Size: 233 KiB |
BIN
public/images/2011/05/2011051421472100.jpg
Normal file
After Width: | Height: | Size: 464 KiB |
BIN
public/images/2011/05/2011051521491300.jpg
Normal file
After Width: | Height: | Size: 478 KiB |
BIN
public/images/2011/05/2011052622280900.jpg
Normal file
After Width: | Height: | Size: 153 KiB |
BIN
public/images/2011/05/2011052622281600.jpg
Normal file
After Width: | Height: | Size: 171 KiB |
BIN
public/images/2011/05/2011052622282200.jpg
Normal file
After Width: | Height: | Size: 241 KiB |
BIN
public/images/2011/05/2011052622285100.jpg
Normal file
After Width: | Height: | Size: 298 KiB |
BIN
public/images/2011/06/2011061816481300.jpg
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
public/images/2011/06/2011061816505900.jpg
Normal file
After Width: | Height: | Size: 89 KiB |
BIN
public/images/2011/06/2011062418273300.jpg
Normal file
After Width: | Height: | Size: 240 KiB |
BIN
public/images/2011/06/2011062418362900.jpg
Normal file
After Width: | Height: | Size: 424 KiB |
BIN
public/images/2011/06/2011062418383500.jpg
Normal file
After Width: | Height: | Size: 332 KiB |
BIN
public/images/2011/06/2011062418552500.jpg
Normal file
After Width: | Height: | Size: 233 KiB |
BIN
public/images/2011/07/2011070220190200.jpg
Normal file
After Width: | Height: | Size: 166 KiB |
BIN
public/images/2011/07/2011070220314300.jpg
Normal file
After Width: | Height: | Size: 93 KiB |
BIN
public/images/2011/07/2011070220315100.jpg
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
public/images/2011/07/2011070220315800.jpg
Normal file
After Width: | Height: | Size: 87 KiB |
BIN
public/images/2011/07/2011070220320500.jpg
Normal file
After Width: | Height: | Size: 203 KiB |
BIN
public/images/2011/07/2011070220322300.jpg
Normal file
After Width: | Height: | Size: 112 KiB |
BIN
public/images/2011/07/2011070220323300.jpg
Normal file
After Width: | Height: | Size: 110 KiB |
BIN
public/images/2011/07/2011070220324000.jpg
Normal file
After Width: | Height: | Size: 122 KiB |
BIN
public/images/2011/07/2011070220324800.jpg
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
public/images/2011/07/2011070220325600.jpg
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
public/images/2011/07/2011070220330400.jpg
Normal file
After Width: | Height: | Size: 89 KiB |
BIN
public/images/2011/07/2011070220331000.jpg
Normal file
After Width: | Height: | Size: 108 KiB |
BIN
public/images/2011/07/2011070220331700.jpg
Normal file
After Width: | Height: | Size: 94 KiB |
BIN
public/images/2011/07/2011070220332300.jpg
Normal file
After Width: | Height: | Size: 94 KiB |
BIN
public/images/2011/07/2011070220332900.jpg
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
public/images/2011/07/2011070220544000.jpg
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
public/images/2011/07/2011070220550500.jpg
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
public/images/2011/07/2011070220552500.jpg
Normal file
After Width: | Height: | Size: 71 KiB |
BIN
public/images/2011/07/2011070220554100.jpg
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
public/images/2011/07/2011070220560200.jpg
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
public/images/2012/01/2012011519234100.jpg
Normal file
After Width: | Height: | Size: 332 KiB |
BIN
public/images/2012/01/2012011819285800.jpg
Normal file
After Width: | Height: | Size: 357 KiB |
BIN
public/images/2012/01/2012011819343900.jpg
Normal file
After Width: | Height: | Size: 206 KiB |
BIN
public/images/2012/02/2012020222465000.jpg
Normal file
After Width: | Height: | Size: 362 KiB |
BIN
public/images/2012/02/2012020521241800.jpg
Normal file
After Width: | Height: | Size: 326 KiB |
BIN
public/images/2012/02/2012020521304400.jpg
Normal file
After Width: | Height: | Size: 232 KiB |
BIN
public/images/2012/02/2012020521334700.jpg
Normal file
After Width: | Height: | Size: 281 KiB |
BIN
public/images/2012/02/2012020821400300.jpg
Normal file
After Width: | Height: | Size: 631 KiB |
BIN
public/images/2012/02/2012020821442400.jpg
Normal file
After Width: | Height: | Size: 289 KiB |
BIN
public/images/2012/02/2012020821481600.jpg
Normal file
After Width: | Height: | Size: 548 KiB |
BIN
public/images/2012/02/2012020922491700.jpg
Normal file
After Width: | Height: | Size: 329 KiB |