Skip to content

Commit

Permalink
Merge pull request #155 from oskariorg/release/1.1
Browse files Browse the repository at this point in the history
Release/1.1
  • Loading branch information
ZakarFin authored Oct 17, 2024
2 parents 63e48c7 + 5a289cb commit 22dec1e
Show file tree
Hide file tree
Showing 23 changed files with 5,212 additions and 3,248 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node: [ 16 ]
node: [ 20 ]

steps:
- uses: actions/checkout@v3
Expand Down
43 changes: 23 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:
Requires `nodejs` version 18 or higher

1) After cloning, run `npm install` to install dependencies
2) Generate documentation
- For dummy content run `npm run dummy_docs` OR
- For actual content see "Generating versioned documentation" below
3) Start the development server:

```bash
npm run dev
Expand All @@ -16,32 +21,30 @@ Open [http://localhost:3000](http://localhost:3000) with your browser to see the

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

## Generating versioned documentation

Clone documentation repos in parallel folders next to this one

1) clone https://github.com/oskariorg/oskari-documentation -> (Should be found in `../oskari-documentation`)
2) clone https://github.com/oskariorg/oskari-frontend -> (Should be found in `../oskari-frontend`)
3) clone https://github.com/oskariorg/oskari-server -> (Should be found in `../oskari-server`)
4) Run `npm run docs [version]` where `[version]` is like `2.13.0`
4) Run `npm run docs [version] [bln_latest]` where:
- `[version]` is like `2.13.0` (defaults to unreleased)
- `[bln_latest]` is like `true` (defaults to false)

This:
- shovels in everything under `oskari-documentation` to `_content/docs/[version]/`
- copies `ReleaseNotes.md` and `api/CHANGELOG.md` to `_content/docs/[version]/[ordinal] Changelog/`

## Learn More

This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
92 changes: 92 additions & 0 deletions app/blog/blogPageNavigationComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/20/solid';
import { useSearchParams } from 'next/navigation';
import React, { useCallback } from 'react';

export const BLOG_POSTS_PER_PAGE = 9
interface NavigationComponentProps {
currentPage: number;
totalPages: number;
totalPosts: number;
handleSetPage: (currentPage: number, queryString: string) => void;
paginatedPostsLength: number;
};

export default function BlogPageNavigationComponent({ handleSetPage, currentPage, totalPages, totalPosts, paginatedPostsLength }: NavigationComponentProps) {
const searchParams = useSearchParams()!
const createQueryString = useCallback(
(name: string, value: string) => {
const params = new URLSearchParams(searchParams)
params.set(name, value)

return params.toString()
},
[searchParams]
)

const pageNumbers = Array.from(
{ length: totalPages },
(_, index) => index + 1
)

return <>
<nav className='mt-16 mb-4' aria-label='Page navigation'>
<div
className='grid grid-cols-[0.5fr_2fr_0.5fr] gap-4 items-center'
style={{ gridColumn: '1' }}
>
{currentPage > 1 && (
<div className='flex justify-start'>
<button
onClick={() => handleSetPage(currentPage -1, createQueryString('page', (currentPage - 1).toString()))}
className='bg-black text-white rounded-full w-12 h-12 grid place-content-center relative'
aria-label={`Go to page ${currentPage - 1}`}
>
<ArrowLeftIcon className='w-6 h-6' />
</button>
</div>
)}
<div style={{ gridColumn: '2' }} className='flex justify-center'>
<div className='flex w-full justify-center gap-4 items-center'>
<label
htmlFor='page-number'
className='block font-semibold text-sm'
>
Page
</label>
<select
id='page-number'
className='bg-black text-white rounded-lg focus:ring-blue-500 focus:border-blue-500 block dark:placeholder-gray-400 text-center h-8 w-14'
onChange={(e) => handleSetPage(parseInt(e.target.value), createQueryString('page', parseInt(e.target.value).toString()))}
value={currentPage}
>
{pageNumbers.map((number) => (
<option key={number} value={number}>
{number}
</option>
))}
</select>
</div>
</div>
{currentPage < totalPages && (
<div className='flex justify-end'>
<button
onClick={() => handleSetPage(currentPage + 1, createQueryString('page', (currentPage + 1).toString()))}
className='bg-black text-white rounded-full w-12 h-12 grid place-content-center relative'
aria-label={`Go to page ${currentPage + 1}`}
>
<ArrowRightIcon className='w-6 h-6' />
</button>
</div>
)}
</div>
</nav>
<div className='grid place-content-center text-center text-gray-500 text-sm'>
{paginatedPostsLength > 0
? `Showing ${(currentPage - 1) * BLOG_POSTS_PER_PAGE + 1} to ${Math.min(
currentPage * BLOG_POSTS_PER_PAGE,
totalPosts
)} of ${totalPosts} posts`
: 'No entries to display'}
</div>
</>;
}
104 changes: 18 additions & 86 deletions app/blog/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ import allPosts from '@/_content/blog/';
import Card from '@/components/Cards/Card';
import Layout from '@/components/Layout';
import styles from '@/styles/blog.module.scss';
import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/20/solid';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { useCallback } from 'react'

import { usePathname, useRouter } from 'next/navigation';
import BlogPageNavigationComponent, { BLOG_POSTS_PER_PAGE } from './blogPageNavigationComponent';
import { Suspense, useState } from 'react';
export default function BlogsPage() {
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()!

const [page, setPage] = useState('1');
const posts = allPosts.map((post) => {
const image = post?.image ?
post.image : (post?.imagesFromPost && post.imagesFromPost.length) > 0 ?
Expand All @@ -27,101 +26,34 @@ export default function BlogsPage() {
return item
}).sort((a, b) => b.date.getTime() - a.date.getTime())

const createQueryString = useCallback(
(name: string, value: string) => {
const params = new URLSearchParams(searchParams)
params.set(name, value)

return params.toString()
},
[searchParams]
)

const POSTS_PER_PAGE = 9

const page = searchParams.get('page') || '1'
const currentPage = parseInt(page)
const totalPages = Math.ceil(posts?.length / POSTS_PER_PAGE)
const totalPages = Math.ceil(posts?.length / BLOG_POSTS_PER_PAGE)
const paginatedPosts = posts?.slice(
(currentPage - 1) * POSTS_PER_PAGE,
currentPage * POSTS_PER_PAGE
(currentPage - 1) * BLOG_POSTS_PER_PAGE,
currentPage * BLOG_POSTS_PER_PAGE
)

const handleSetPage = (page: number) => {
router.push(`${pathname}?${createQueryString('page', page.toString())}`)
const handleSetPage = (currentPage: number, queryString: string) => {
setPage('' + currentPage);
router.push(`${pathname}?${queryString}`)
}

const pageNumbers = Array.from(
{ length: totalPages },
(_, index) => index + 1
)

return (
<Layout heroTitle='Blog' heroSmall>
<div className='container--content'>
<div className={styles.blog__grid}>
{paginatedPosts?.map((item) => <Card data={item} key={item.title} />)}
</div>
<nav className='mt-16 mb-4' aria-label='Page navigation'>
<div
className='grid grid-cols-[0.5fr_2fr_0.5fr] gap-4 items-center'
style={{ gridColumn: '1' }}
>
{currentPage > 1 && (
<div className='flex justify-start'>
<button
onClick={() => handleSetPage(currentPage - 1)}
className='bg-black text-white rounded-full w-12 h-12 grid place-content-center relative'
aria-label={`Go to page ${currentPage - 1}`}
>
<ArrowLeftIcon className='w-6 h-6' />
</button>
</div>
)}
<div style={{ gridColumn: '2' }} className='flex justify-center'>
<div className='flex w-full justify-center gap-4 items-center'>
<label
htmlFor='page-number'
className='block font-semibold text-sm'
>
Page
</label>
<select
id='page-number'
className='bg-black text-white rounded-lg focus:ring-blue-500 focus:border-blue-500 block dark:placeholder-gray-400 text-center h-8 w-14'
onChange={(e) => handleSetPage(parseInt(e.target.value))}
value={currentPage}
>
{pageNumbers.map((number) => (
<option key={number} value={number}>
{number}
</option>
))}
</select>
</div>
</div>
{currentPage < totalPages && (
<div className='flex justify-end'>
<button
onClick={() => handleSetPage(currentPage + 1)}
className='bg-black text-white rounded-full w-12 h-12 grid place-content-center relative'
aria-label={`Go to page ${currentPage + 1}`}
>
<ArrowRightIcon className='w-6 h-6' />
</button>
</div>
)}
</div>
</nav>
<div className='grid place-content-center text-center text-gray-500 text-sm'>
{paginatedPosts && paginatedPosts.length > 0
? `Showing ${(currentPage - 1) * POSTS_PER_PAGE + 1} to ${Math.min(
currentPage * POSTS_PER_PAGE,
posts.length
)} of ${posts.length} posts`
: 'No entries to display'}
</div>
</div>
<Suspense>
<BlogPageNavigationComponent
handleSetPage={handleSetPage}
currentPage={currentPage}
totalPages={totalPages}
totalPosts={posts?.length}
paginatedPostsLength={paginatedPosts.length}/>
</Suspense>
</Layout>
)
}
2 changes: 1 addition & 1 deletion app/discover/gettingstarted/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const metadata: Metadata = {

export default function GettingStartedPage() {
return (
<Layout heroSmall heroTitle='Getting Started'>
<Layout heroSmall heroTitle='Getting Started' decorateLinks={true}>
<div>
<Text>
This site contains all the relevant links for finding the information you need about Oskari. The material has been divided under different user groups and customed to their needs.
Expand Down
1 change: 0 additions & 1 deletion app/documentation/api/bundles/[version]/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,5 @@ export default async function BundlesContentPage({
version={params.version}
sideBarContent={<BundlesSidebarContent elements={bundles} baseHref={bundleBaseRef}/>}
mainContent={<HtmlContentPage mdPath={bundlesBasePath + '/' + foundItem.path + '/bundle.md'} imagesPath={imagesPath} />}
title='Oskari API documentation'
baseHref='/documentation/api/bundles/'/>;
}
1 change: 0 additions & 1 deletion app/documentation/api/bundles/[version]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,5 @@ export default async function BundlesVersionPage({
version={params.version}
sideBarContent={<BundlesSidebarContent elements={bundles} baseHref={bundleBaseRef}/>}
mainContent={<ApiDocChangeLog version={params.version}/>}
title='Oskari API documentation'
baseHref='/documentation/api/bundles/'/>;
}
15 changes: 15 additions & 0 deletions app/documentation/api/bundles/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import DefaultLayout from '@/components/Layout'
import { Suspense } from 'react'
import Loading from '../../docs/loading'

export default function Layout({ children }: { children: React.ReactNode }) {
return (
<DefaultLayout heroSmall heroTitle={'Oskari API Documentation'}>
<div className='container--content'>
<div className='layout--docs'>
<Suspense fallback={<Loading />}>{children}</Suspense>
</div>
</div>
</DefaultLayout>
)
}
20 changes: 20 additions & 0 deletions app/documentation/api/components/ApiDocsLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import DefaultLayout from '@/components/Layout'
import { Suspense } from 'react'
import Loading from '../../docs/loading'

/**
* This way is "wrong". We should instead use layout in a more orderly nextjs fashion
* This will need some refactoring at some point. This is just a quick and dirty solution
* to make app work just like before even after migration to nextjs 14
*/
export default function ApiDocsLayout({ children }: { children: React.ReactNode }) {
return (
<DefaultLayout heroSmall heroTitle={'Oskari API Documentation'}>
<div className='container--content'>
<div className='layout--docs'>
<Suspense fallback={<Loading />}>{children}</Suspense>
</div>
</div>
</DefaultLayout>
)
}
7 changes: 2 additions & 5 deletions app/documentation/api/components/ApiSectionContentPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@
import VersionSidebar from '@/components/VersionSidebar';
import { compareSemanticVersions } from '@/utils/misc';
import availableVersions from '_content/api/versions'
import Layout from '../../docs/layout';
import { ReactNode } from 'react';
export default function ApiSectionContentPage({
title,
sideBarContent,
mainContent,
baseHref,
version
}: {
title: string,
sideBarContent: ReactNode,
mainContent: ReactNode,
baseHref: string,
Expand All @@ -25,13 +22,13 @@ export default function ApiSectionContentPage({
),
];

return <Layout heroTitle={title}>
return <>
<div>
<VersionSidebar selectedVersion={version} versions={versions} baseHref={baseHref} />
{sideBarContent}
</div>
<div className={'overFlowHidden'}>
{mainContent}
</div>
</Layout>;
</>;
}
Loading

0 comments on commit 22dec1e

Please sign in to comment.