diff --git a/src/app/App.tsx b/src/app/App.tsx
index b9ccce5f..c74e58c5 100644
--- a/src/app/App.tsx
+++ b/src/app/App.tsx
@@ -5,7 +5,7 @@ import '../styles/nodes.css'
import { Analytics } from './Analytics.js'
import { cleanUrl } from './Utils.js'
import { Header } from './components/index.js'
-import { Changelog, Customized, Generator, Generators, Guide, Guides, Home, Partners, Sounds, Transformation, Versions, Worldgen } from './pages/index.js'
+import { Changelog, Customized, Generator, Generators, Guide, Guides, Home, Partners, Sounds, Transformation, Versions, WhatsNew, Worldgen } from './pages/index.js'
export function App() {
const changeRoute = (e: RouterOnChangeArgs) => {
@@ -26,6 +26,7 @@ export function App() {
+
diff --git a/src/app/components/Octicon.tsx b/src/app/components/Octicon.tsx
index 2adb2d03..4824ab60 100644
--- a/src/app/components/Octicon.tsx
+++ b/src/app/components/Octicon.tsx
@@ -36,6 +36,7 @@ export const Octicon = {
link_external: ,
lock: ,
mark_github: ,
+ megaphone: ,
moon: ,
mortar_board: ,
package: ,
diff --git a/src/app/pages/Home.tsx b/src/app/pages/Home.tsx
index 60698c96..60ae371b 100644
--- a/src/app/pages/Home.tsx
+++ b/src/app/pages/Home.tsx
@@ -1,12 +1,12 @@
import { useMemo } from 'preact/hooks'
import contributors from '../../contributors.json'
-import { ChangelogEntry, Footer, GeneratorCard, Giscus, GuideCard, ToolCard, ToolGroup } from '../components/index.js'
+import { Store } from '../Store.js'
+import { shuffle } from '../Utils.js'
+import { Card, ChangelogEntry, Footer, GeneratorCard, Giscus, GuideCard, ToolCard, ToolGroup } from '../components/index.js'
import { useLocale, useTitle } from '../contexts/index.js'
import { useAsync } from '../hooks/useAsync.js'
import { useMediaQuery } from '../hooks/useMediaQuery.js'
-import { fetchChangelogs, fetchVersions } from '../services/DataFetcher.js'
-import { Store } from '../Store.js'
-import { shuffle } from '../Utils.js'
+import { fetchChangelogs, fetchVersions, fetchWhatsNew } from '../services/DataFetcher.js'
const MIN_FAVORITES = 2
const MAX_FAVORITES = 5
@@ -30,6 +30,7 @@ export function Home({}: Props) {
{smallScreen && }
{smallScreen && }
+
{!smallScreen &&
@@ -135,7 +136,15 @@ function Changelog() {
}
+function WhatsNew() {
+ const { locale } = useLocale()
+ const { value: items } = useAsync(fetchWhatsNew)
+
+ return
+ {items?.slice(0, 3).map(item => {item.title})}
+
+}
function Contributors() {
const supporters = useMemo(() => {
diff --git a/src/app/pages/WhatsNew.tsx b/src/app/pages/WhatsNew.tsx
new file mode 100644
index 00000000..e8226b30
--- /dev/null
+++ b/src/app/pages/WhatsNew.tsx
@@ -0,0 +1,38 @@
+import { marked } from 'marked'
+import { ErrorPanel, Footer } from '../components/index.js'
+import { useLocale, useTitle } from '../contexts/index.js'
+import { useAsync } from '../hooks/useAsync.js'
+import type { WhatsNewItem } from '../services/DataFetcher.js'
+import { fetchWhatsNew } from '../services/DataFetcher.js'
+
+interface Props {
+ path?: string,
+}
+export function WhatsNew({}: Props) {
+ const { locale } = useLocale()
+ useTitle(locale('title.whats_new'))
+
+ const { value: items, error } = useAsync(fetchWhatsNew)
+
+ return
+
+
{locale('whats_new.description')}
+ {error &&
}
+ {items?.map(item =>
)}
+
+
+
+}
+
+interface EntryProps {
+ item: WhatsNewItem,
+}
+function WhatsNewEntry({ item }: EntryProps) {
+ return
+
+
+ {item.title}
+
+
+
+}
diff --git a/src/app/pages/index.ts b/src/app/pages/index.ts
index fe69d102..7f7999be 100644
--- a/src/app/pages/index.ts
+++ b/src/app/pages/index.ts
@@ -9,4 +9,5 @@ export * from './Partners.js'
export * from './Sounds.js'
export * from './Transformation.jsx'
export * from './Versions.js'
+export * from './WhatsNew.jsx'
export * from './Worldgen.jsx'
diff --git a/src/app/services/DataFetcher.ts b/src/app/services/DataFetcher.ts
index 18c1031e..2b4fb4c4 100644
--- a/src/app/services/DataFetcher.ts
+++ b/src/app/services/DataFetcher.ts
@@ -19,6 +19,7 @@ const mcmetaUrl = 'https://raw.githubusercontent.com/misode/mcmeta'
const mcmetaTarballUrl = 'https://github.com/misode/mcmeta/tarball'
const changesUrl = 'https://raw.githubusercontent.com/misode/technical-changes'
const fixesUrl = 'https://raw.githubusercontent.com/misode/mcfixes'
+const whatsNewUrl = 'https://whats-new.misode.workers.dev/'
type McmetaTypes = 'summary' | 'data' | 'data-json' | 'assets' | 'assets-json' | 'registries' | 'atlas'
@@ -280,6 +281,23 @@ export async function fetchBugfixes(version: VersionId): Promise
{
}
}
+export interface WhatsNewItem {
+ id: string,
+ title: string,
+ body: string,
+ url: string,
+ createdAt: string,
+}
+
+export async function fetchWhatsNew(): Promise {
+ try {
+ const whatsNew = await cachedFetch(whatsNewUrl, { refresh: true })
+ return whatsNew
+ } catch (e) {
+ throw new Error(`Error occured while fetching what's new: ${message(e)}`)
+ }
+}
+
interface FetchOptions {
decode?: (r: Response) => Promise
refresh?: boolean
diff --git a/src/locales/en.json b/src/locales/en.json
index 2622b384..173df914 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -144,6 +144,7 @@
"title.sounds": "Sound Explorer",
"title.transformation": "Transformation Visualizer",
"title.versions": "Versions Explorer",
+ "title.whats_new": "What's new?",
"title.worldgen": "Worldgen Generators and Guides",
"tools": "Tools",
"transformation.matrix": "Matrix",
@@ -252,6 +253,8 @@
"versions.latest_snapshot": "Latest snapshot",
"versions.latest_release": "Latest release",
"weight": "Weight",
+ "whats_new": "What's new?",
+ "whats_new.description": "Stay informed about all the latest development on misode.github.io. Read below to find out which features have recently been added.",
"world": "World Settings",
"worldgen": "Worldgen",
"worldgen/biome": "Biome",
diff --git a/src/styles/global.css b/src/styles/global.css
index ecd365ca..89e54d1a 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -2369,6 +2369,69 @@ hr {
z-index: 4;
}
+.whats-new > p {
+ color: var(--text-2);
+ padding-bottom: 30px;
+}
+
+.whats-new-entry {
+ padding-bottom: 50px;
+ position: relative;
+ padding-left: 46px;
+}
+
+.whats-new-entry:last-child {
+ padding-bottom: 10px;
+}
+
+.whats-new-entry::before {
+ content: '';
+ background-color: var(--background-6);
+ position: absolute;
+ top: 17px;
+ bottom: -2px;
+ left: 20px;
+ width: 2px;
+}
+
+.whats-new-entry::after {
+ content: '';
+ position: absolute;
+ top: 2px;
+ left: 13px;
+ background-color: var(--background-1);
+ border: 3px solid var(--text-1);
+ border-radius: 10px;
+ width: 10px;
+ height: 10px;
+}
+
+.whats-new-entry > a {
+ display: block;
+ text-decoration: none;
+}
+
+.whats-new-entry time {
+ color: var(--text-3);
+ font-size: 15px;
+}
+
+.whats-new-entry h2 {
+ color: var(--text-1);
+ padding: 10px 0 15px;
+}
+
+.whats-new-entry .guide-content {
+ margin-top: 0;
+}
+
+.whats-new-entry .guide-content img {
+ max-width: min(calc(100vw - 78px), 600px);
+ background: linear-gradient(150deg, var(--background-6) 0%, var(--background-5) 100%);
+ padding: 20px;
+ display: block;
+}
+
.ace_editor,
.ace_gutter,
.ace_gutter .ace_layer,