Skip to content

Configuration reference ​

The root blog.config.ts configures the theme; friends.config.ts stores friend links separately. Articles, pages, categories and tags use frontmatter. Restart development after changing configuration, and rebuild and redeploy production.

This page covers every public BlogConfig, NavigationItem and FriendsConfig field. Types live in src/types/config.ts.

Required fields and defaults ​

  • Required means the field must remain in the configuration; there is no automatic runtime completion. An initial value is the value supplied by the repository, which you may change.
  • Optional fields may be omitted. Their actual omission behavior is documented below. Partial nested settings inherit field by field; include only fields you want to override.
  • Localized is the text type described below. Booleans must be true or false, not strings such as 'false'. An empty array [] provides no entries.
  • Snippets represent parts of the existing configuration. Keep the root const config: BlogConfig = { ... } and export default config.

Localized interface copy ​

Use a string, or a nonempty map Partial<Record<string, string>>. Keys accept any valid BCP 47 code, including ja and pt-BR. Strings stay the same in every interface. Maps translate names and descriptive copy.

ts
site: { /* retain other fields */ title: { zh: '我的站点', en: 'My site' } },
author: {
  // retain other fields
  name: { zh: '站点作者', en: 'Site author' },
  bio: { zh: '关于这个站点的一句话。', en: 'A sentence about this site.' },
},

Resolution order: requested language and parent tags → site.defaultLocale and its parent tags → site.locales order → first available map value. An empty string intentionally clears text. A map needs at least one valid BCP 47 key; omitted languages follow the resolution order above.

Localized fields include site and author names and biography, social labels, all text copy values (including tabs), navigation names/descriptions, share copy formats and platform names, footer author names, group names/descriptions and linked-site names/descriptions. URLs, slugs, paths, icon IDs, theme IDs and timezones remain ordinary strings.

site: identity and deployment ​

FieldTypeRequiredInitial valueMeaning and input
siteobjectYesFields belowSite basics.
site.titleLocalizedYes'BlogGPT'Sidebar name, browser title, RSS, sharing text and share-card branding.
site.baseUrlstringYes'https://example.com/'Complete production root with protocol and optional subdirectory, e.g. https://example.org/blog/. Derives origin and deployment path and adds a trailing slash; credentials, query and fragment are forbidden. Used for assets, navigation, canonical, feeds, Sitemap and sharing.
site.defaultLocaleBCP 47 stringYes'zh'Default copy/content language and default destination under the selected prefix policy; must be in locales.
site.localesLocale[]Yes['zh', 'en']Content languages built by the site, independent of registered UI packs; accepts any valid BCP 47 code; nonempty and unique. Order also participates in missing-translation selection. Keep one code for a single-language site.
site.localePrefixPolicy'redirect-to-default' / 'omit-default-prefix' / 'require-prefix'No'redirect-to-default'Omitted: zero-second meta refresh from unprefixed HTML URLs directly to final default-language pages. omit-default-prefix: build the default language only without a prefix. require-prefix: unprefixed URLs return 404. See language prefix policies.
site.timezonestringYes'Asia/Shanghai'Valid IANA timezone, such as UTC. Controls displayed dates, archives, statistics and elapsed days.
FieldTypeRequiredInitial valueMeaning and input
authorobjectYesFields belowAuthor menu and article attribution.
author.nameLocalizedYes'Astro Theme BlogGPT'Display name, also used in sharing and generated cards.
author.bioLocalizedYesWelcome to the BlogGPT theme demo site!Bottom-left author details and menu biography. Accepts a string or localized map; use an empty string to leave it blank.
author.avatarstringYes'/images/avatar.webp'Public local path or full image URL. public/avatar.webp is /avatar.webp; base is handled by the theme.
author.socialsarrayYesGitHub, YouTube and email examplesDisplay order follows the array. [] removes social entries. Replace sample URLs.
author.socials[].labelLocalizedYesPlatform namesMenu text and accessible name.
author.socials[].iconstringYese.g. 'simple-icons:github'Simple Icons for brands, e.g. simple-icons:youtube; lucide:mail for generic actions. Missing namespace defaults to Simple Icons in social controls.
author.socials[].hrefstringYesexample.com or email placeholderFull destination or mailto:hello@example.org.

text: descriptive copy ​

The text object and the copy fields below are required. Copy values use Localized; text.tabs is a required object containing search and posts. Empty strings clear copy. The table lists repository example copy; all language values live in blog.config.ts.

FieldExample copyLocation and effect
text.siteDescriptionAn Astro blog theme inspired by ChatGPT's layout.Default SEO description, site-title supplement and RSS description. Entry descriptions take priority on content pages.
text.homeHeadingWhat would you like to read today?Large heading above home search.
text.tabssearch, postsRequired top-Tab copy object; both children are required and can be translated independently.
text.tabs.searchReadFirst top Tab, linking to the homepage search interface; accepts Localized.
text.tabs.postsArticlesSecond top Tab, linking to the article list; accepts Localized.
text.searchHeadingEnter keywords to discover an articleSearch-page and empty-search prompt.
text.searchPlaceholderSearch articles, ideas and keywordsSearch input placeholder.
text.notFoundMessageThis page has no story yet.404 body message; does not change HTTP status.
text.footerDescriptionBlogGPT theme demo · Sample content ready to customize.Second footer line, suitable for a copyright/content notice.

Generic action labels such as Search or Copied are maintained by the central packs under src/i18n/, registered in src/i18n/i18n.config.ts, rather than public blog.config.ts fields.

appearance: visual defaults ​

FieldTypeRequiredInitial valueMeaning and differences
appearanceobjectYesFields belowGlobal appearance.
appearance.defaultThemelight / dark / systemYes'system'New visitors use light, dark or system appearance. Saved browser preferences take priority.
appearance.pageTransitionfade / noneYes'fade'fade briefly fades article content; none disables that transition while retaining Astro client navigation. Reduced-motion preferences are respected.
appearance.codeThemesobjectYesFields belowLight and dark code themes.
appearance.codeThemes.lightShiki theme nameYes'github-light'Supported installed Shiki / Expressive Code theme for light mode.
appearance.codeThemes.darkShiki theme nameYes'github-dark'Dark-mode theme, e.g. dracula. Unknown names fail the build.
appearance.showCodeLineNumbersbooleanYesfalseDefault code line-number visibility.
appearance.categoryCoverStylethumbnail / fade / backgroundYes'thumbnail'Small thumbnail; right-side image fading left; or full-card background with overlay. Category coverStyle overrides it. Entries without images stay plain cards.
FieldTypeRequiredInitial valueMeaning and constraints
sidebarobjectYesFields belowSidebar and site-name menu.
sidebar.itemsNavigationItem[]YesHome, articles, categories, archives, friends, About, theme repository, BlogGPT docsFixed sidebar entries and order; [] clears fixed navigation.
sidebar.menuNavigationItem[]YesHome, articles, About, theme repository, BlogGPT docsIndependent top-left site-name menu.
sidebar.widthobjectYesFields belowDesktop draggable width, in px.
sidebar.width.defaultnumberYes340Initial width without a saved browser preference.
sidebar.width.minnumberYes240Minimum width, at least 200.
sidebar.width.maxnumberYes480Maximum width, at most 600; min ≤ default ≤ max.

Every NavigationItem field ​

Provide common fields, then the fields required by type. UI icons use Lucide; files and lucide:files both work.

FieldTypeRequiredOmission behavior and meaning
idstringYesStable unique identifier such as about; avoid duplicates within a menu.
labelLocalizedYesDisplayed navigation name.
iconstringsidebar.items only, requiredSidebar items use Lucide or Simple Icons. sidebar.menu does not have this field.
descriptionLocalizedNoNo secondary description when omitted; supplies menu supporting text when present.
typebuiltin / page / externalYesBuiltin feature, standalone content, or external destination.
routebuiltin IDRequired for builtinhome, posts, categories, archives, links or tags; an identifier, not a URL. Omit for other types.
pagestringRequired for page; optional for builtinA pages slug, not a source path. Page entries link to standalone pages; posts/categories/tags/archives/links bindings place its title, description and body before the feature. Home has no introduction binding. No binding uses the default title and an empty body; missing bound content raises an error.
hrefstringRequired for externalFull external address; unused for other types.
newTabbooleanOptional for externalDefault false uses this tab; true opens a new tab.
ts
{ id: 'about', type: 'page', page: 'about', label: { zh: '关于', en: 'About' }, icon: 'info' },
{ id: 'topics', type: 'builtin', route: 'categories', page: 'categories', label: 'Topics', icon: 'shapes' },
{ id: 'docs', type: 'external', href: 'https://docs.astro.build/', newTab: true, label: 'Astro', icon: 'globe' },

Keep page bindings consistent when the same route appears in both menus. The first matching binding is selected in items then menu order. Introductions belong to pages, not posts. See taxonomy and pages.

posts: lists and dates ​

FieldTypeRequiredInitial valueMeaning
postsobjectYesFields belowArticle-list settings.
posts.pathPrefixstringNo''Directory between posts/ and the slug. Prefer [year]/, [year]/[month]/ or notes/[year]/; the trailing slash is optional and normalized internally. Date placeholders use site.timezone. No leading slash, empty segments, query, traversal or reserved page prefix. Rebuild and migrate old links after changes.
posts.perPagepositive integerYes5Articles per listing page.
posts.homeLimitpositive integerYes4Homepage article count.
posts.menuLimitpositive integerYes12Recent articles shown in the plus menu. Values above the article count (e.g. 99999) include all posts; does not limit the full sidebar list.
posts.randomLimitpositive integerYes12Recent candidates for the random button and /random, ordered by publication time. 99999 includes all; independent of menuLimit.
posts.showDraftsInDevbooleanYestruePreview draft and future content in development; false limits preview to published content. It never publishes drafts in production.
posts.dateFormatIntl.DateTimeFormatOptionsYesNative date formatting; locale follows the interface, timezone is forced to site.timezone. {} uses Intl's default date format.

Native dateFormat options: year, day, hour, minute and second accept numeric / 2-digit. month also accepts long / short / narrow. weekday, era and dayPeriod accept long / short / narrow. fractionalSecondDigits is 1 / 2 / 3; hour12 is boolean; hourCycle is h11 / h12 / h23 / h24. dateStyle and timeStyle accept full / long / medium / short and cannot be combined with specific components such as year or month.

Other native options are calendar (e.g. gregory), numberingSystem (e.g. latn), localeMatcher (lookup / best fit), formatMatcher (basic / best fit), and timeZoneName (short / long / shortOffset / longOffset / shortGeneric / longGeneric). Omitted values are inferred by Intl. timeZone is always overridden by site.timezone. Invalid combinations or IDs can fail the build; keep the repository format or use only { dateStyle: 'long' }.

article: default reading settings ​

article is required. Feature switches apply where the relevant renderer is used. An explicit frontmatter boolean takes priority; false disables a global feature and true can re-enable one.

FieldTypeRequiredInitial / Omitted valueMeaning
article.mathbooleanYestrueKaTeX math.
article.mermaidbooleanYestrueMermaid diagrams with on-demand client loading.
article.lightboxbooleanYestruePhotoSwipe content-image galleries.
article.calloutsbooleanYestrueConvert NOTE / TIP marked quotes into callouts.
article.displaypartial ArticleDisplayNoEach omitted field is trueVisual reading details for articles and standalone pages.
article.display.authorbooleanNotrueAuthor avatar and name.
article.display.publishedbooleanNotruePublication date; pages without dates have none to display.
article.display.readingTimebooleanNotrueEstimated minutes calculated from body length.
article.display.updatedbooleanNotrueEnd-of-body update date, only when provided and different from publication; no filesystem inference.
article.display.tagsbooleanNotrueBottom article tags; pages have no article-tag relations.
article.display.sharebooleanNotrueShare button and popover.
article.display.navigationbooleanNotruePrevious/next links for articles.
article.display.titlebooleanNotrueTitle, description and categories. Does not remove browser/search titles or control the cover.

Display switches control reading-page details. Article covers appear above titles; list covers appear beside summaries.

article.toc: outline ​

FieldTypeRequiredInitial / Omitted valueMeaning
article.tocobjectYesFields belowDesktop interactive outline and narrow-screen top-right outline panel.
article.toc.enabledbooleanYestrueDefault outline enablement; per-entry toc overrides. No matching headings means no outline.
article.toc.minDepthinteger 1–6Yes2Shallowest heading; 2 means ##.
article.toc.maxDepthinteger 1–6Yes4Deepest heading; cannot be less than minDepth.
article.toc.expandDelaynonnegative millisecondsYes1000Stationary dwell before full expansion; motion restarts the timer.
article.toc.hideDelaynonnegative millisecondsNo800Wait after leaving before automatic dismissal.

The outline includes line previews, drag navigation and visible-section dashed frames. See the interactive outline.

article.shareCover: generated images ​

FieldTypeRequiredInitial / Omitted valueMeaning
article.shareCoverobjectYesFields belowSatori generates PNGs at build time.
article.shareCover.enabledbooleanYestrueDefault enablement; per-entry shareCover overrides. Disabled entries use ordinary covers if present, otherwise no preview image.
article.shareCover.widthinteger 320–4096Yes1200Output width in px.
article.shareCover.heightinteger 320–4096Yes630Output height in px; a landscape ratio is recommended.
article.shareCover.backgroundCSS color stringYes'#f5f5f5'Image background.
article.shareCover.foregroundCSS color stringYes'#171717'Title and text color.
article.shareCover.accentCSS color stringYes'#3b82f6'Branding block color, not site link color.
article.shareCover.fontPathstringNoBundled Noto Sans SCBuild-machine font file, absolute or relative to the project root. Prefer TTF / OTF / WOFF covering the text characters. Not a public URL; a missing file fails the build.

Cards contain the entry title, description and localized site/author names. Results cache in .astro/share-covers/ and regenerate when content, style or font changes. Hover Share on desktop to view the card; there is no separate preview button.

sharing: copied text and destinations ​

FieldTypeRequiredInitial / Omitted valueMeaning
sharingobjectNoDefault copy format, no platformsOmitting the object still permits copied share text and links.
sharing.copyFormatLocalizedNo'{title}\n{description}\n{author} · {blog}\n{url}'Main share-button copy format; \n in a TS string means a newline.
sharing.platformsarrayNoOmitted: []; repository: 15 entriesDisplay order; at most two rows then scroll. [] retains copy controls only.
sharing.platforms[].nameLocalizedYesPlatform namesDisplay name, independent of the API.
sharing.platforms[].iconstringNoName onlySimple Icons for brands; lucide:mail for generic actions.
sharing.platforms[].hrefstringYesPlatform API templatesOnly http, https or mailto. Use a share endpoint, not a homepage. Variables are encoded once; do not pre-encode.

Copy formats use {title}, {description}, {author}, {blog}, {url}, {image}. Destination hrefs additionally accept {text}, the assembled copy message. url/image are production absolute URLs including base; absent descriptions are empty. Unknown placeholders remain unchanged, with no JS execution or recursive replacement.

Repository presets: X, Facebook, LinkedIn, Reddit, Bluesky, Threads, Telegram, WhatsApp, LINE, Weibo, QQ, QQ Space, Tumblr, Pinterest and email. Edit the platform list through platforms; omission uses an empty array. Pinterest requires an image. Platforms handle fetching, login and final publication. See sharing.

statistics: blog statistics ​

The whole object is optional. All boolean fields default to true, and recentLimit defaults to 12. Individual switches hide individual items; enabled removes the dialog, author-menu entry and status command together.

FieldTypeInitial / Omitted valueMeaning
statistics.enabledbooleantrueMaster switch.
statistics.articleCountbooleantruePublic article count.
statistics.wordCountbooleantrueBody character total, excluding fenced code and link URLs.
statistics.daysbooleantrueElapsed days from footer.since to build day.
statistics.languagesbooleantrueEnabled interface languages.
statistics.averageWordsbooleantrueAverage body length per article.
statistics.updateFrequencybooleantrueMean publication interval: newest minus oldest publication divided by article count minus one; fewer than two shows a dash.
statistics.firstPublicationbooleantrueEarliest public publication; empty sites show a dash.
statistics.lastUpdatebooleantrueLatest public article update, with publication as each article's fallback.
statistics.heatmapbooleantrueLast 365 days through build day, grouped by site.timezone. Only dates with articles show entry popovers.
statistics.recentWordsbooleantrueRecent article-length bars ordered by publication, with title/description tooltips.
statistics.recentLimitinteger 1–5012Bar-chart limit, independent of posts.menuLimit and posts.randomLimit.

Only discoverable published articles in the current language count, excluding drafts, future and hidden entries. Figures update on builds; footer statistics are displayed separately.

FieldTypeRequiredInitial valueMeaning
footerobjectYesFields belowThree centered lines.
footer.sincenumber or stringYes2024Year number or valid YYYY-MM-DD string. A year starts January 1; displays copyright range and elapsed days at build time, updated on builds.
footer.authorLocalizedYes'Astro Theme BlogGPT'Copyright name; empty strings use author.name.
footer.showAttributionbooleanYestrueShow Powered by Astro & BlogGPT; false retains the license.
footer.licenseobjectYesFields belowContent license, separate from theme-code licensing.
footer.license.labelstringYes'CC BY-NC-SA 4.0'Plain license name; the final footer row stays in English without translation.
footer.license.urlstringYeshttps://creativecommons.org/licenses/by-nc-sa/4.0/License description link; change it together with its name.

Line one combines copyright, days and article/character totals; line two is text.footerDescription; line three is attribution and license. Set your copyright description in text.footerDescription.

friends.config.ts: friends ​

Export a FriendsConfig array of groups directly. Array order controls display order; [] means no friends. The title, description and introductory body come from content/pages/links/index.[lang].md, bound through page: 'links' in navigation, rather than this configuration.

FieldTypeRequiredInitial value / OmissionMeaning
friends[]group arrayYesFour example groupsGroups appear in array order.
friends[].titleLocalizedYesGroup nameGroup heading.
friends[].descriptionLocalizedNoHiddenGroup description.
friends[].linksarrayYesExample linksOrdered cards; an empty array is allowed.
friends[].links[].nameLocalizedYesSite nameSearchable card title.
friends[].links[].descriptionLocalizedYesSite descriptionSearchable description; an empty string is allowed.
friends[].links[].urlstringYesSite URLFull destination URL.
friends[].links[].avatarstringNoUses iconRounded square image: full URL or a public path. Local paths receive the deployment prefix. An avatar takes priority.
friends[].links[].iconstringNo'globe'Lucide fallback without avatar; accepts book-open or lucide:book-open. Avatars take priority when present.
ts
import type { FriendsConfig } from './src/types/config';

const friends: FriendsConfig = [
  {
    title: { zh: '资源', en: 'Resources' },
    links: [
      {
        name: 'Astro',
        description: { zh: '官方文档', en: 'Documentation' },
        url: 'https://docs.astro.build/',
        icon: 'book-open', // An avatar may be configured instead and takes priority.
      },
    ],
  },
];
export default friends;

Interface language registry ​

src/i18n/i18n.config.ts registers interface translations from the same directory and is maintained by theme and community contributors. This registry supplies theme interface copy only. Site owners choose content languages through site.locales independently of UI registration; missing interface translations use fallback copy. Each language has required label: string and messages: Partial<Messages> and optional dir: 'ltr' | 'rtl' (inferred when omitted). Keys are BCP 47 codes. Enable routes in site.locales; registration alone does not generate pages. Partial UI packs inherit the default language then English, with regional parent fallback. See the complete language guide.

Next steps ​

Start with site and appearance for addresses, identity, copy and dates, then navigation and friends. Per-entry fields and inheritance are in frontmatter.

BlogGPT · Documentation