diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..4d765f2 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": ["next/core-web-vitals", "prettier"] +} diff --git a/.github/workflows/nextjs.yml b/.github/workflows/nextjs.yml new file mode 100644 index 0000000..c15d423 --- /dev/null +++ b/.github/workflows/nextjs.yml @@ -0,0 +1,110 @@ +name: Deploy Next.js site to Pages + +on: + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Build job + build: + runs-on: ubuntu-latest + strategy: + matrix: + job: ["prettier", "build"] + + env: + NEXT_PUBLIC_CONTENTFUL_SPACE_ID: ${{ secrets.NEXT_PUBLIC_CONTENTFUL_SPACE_ID }} + NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN: ${{ secrets.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN }} + NEXT_PUBLIC_GOOGLE_ANALYTICS_ID: ${{ secrets.NEXT_PUBLIC_GOOGLE_ANALYTICS_ID }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + - uses: pnpm/action-setup@v3 + with: + version: 8 + - name: Detect package manager + id: detect-package-manager + run: | + if [ -f "${{ github.workspace }}/pnpm-lock.yaml" ]; then + echo "manager=pnpm" >> $GITHUB_OUTPUT + echo "command=install" >> $GITHUB_OUTPUT + echo "runner=pnpm" >> $GITHUB_OUTPUT + exit 0 + elif [ -f "${{ github.workspace }}/yarn.lock" ]; then + echo "manager=yarn" >> $GITHUB_OUTPUT + echo "command=install" >> $GITHUB_OUTPUT + echo "runner=yarn" >> $GITHUB_OUTPUT + exit 0 + elif [ -f "${{ github.workspace }}/package.json" ]; then + echo "manager=npm" >> $GITHUB_OUTPUT + echo "command=ci" >> $GITHUB_OUTPUT + echo "runner=npx --no-install" >> $GITHUB_OUTPUT + exit 0 + else + echo "Unable to determine package manager" + exit 1 + fi + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: ${{ steps.detect-package-manager.outputs.manager }} + - name: Setup Pages + uses: actions/configure-pages@v5 + with: + # Automatically inject basePath in your Next.js configuration file and disable + # server side image optimization (https://nextjs.org/docs/api-reference/next/image#unoptimized). + # + # You may remove this line if you want to manage the configuration yourself. + static_site_generator: next + - name: Restore cache + uses: actions/cache@v4 + with: + path: | + .next/cache + # Generate a new cache whenever packages or source files change. + key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }} + # If source files changed but packages didn't, rebuild from a prior cache. + restore-keys: | + ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}- + - name: Install dependencies + run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} + - name: Check formatting + run: npx prettier --check . + if: matrix.job == 'prettier' + - name: Build with Next.js + run: ${{ steps.detect-package-manager.outputs.runner }} next build + if: matrix.job == 'build' + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./out + if: matrix.job == 'build' + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 0000000..2ef178b --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,34 @@ +name: Playwright Tests +on: + push: + branches: [main, playwright] + pull_request: + branches: [main] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: lts/* + - name: Install dependencies + run: npm install -g pnpm && pnpm install + - name: Build the app + env: + CONTENTFUL_CMA_TOKEN: ${{ secrets.CONTENTFUL_CMA_TOKEN }} + NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN: ${{ secrets.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN }} + NEXT_PUBLIC_CONTENTFUL_SPACE_ID: ${{ secrets.NEXT_PUBLIC_CONTENTFUL_SPACE_ID }} + NEXT_PUBLIC_GOOGLE_ANALYTICS_ID: ${{ secrets.NEXT_PUBLIC_GOOGLE_ANALYTICS_ID }} + run: pnpm build + - name: Install Playwright Browsers + run: pnpm exec playwright install --with-deps + - name: Run Playwright tests + run: pnpm exec playwright test + - uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8555bac --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# vs code +.vscode/ +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..eeeb7be --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +pnpm-lock.yaml \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..33a3ebc --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "trailingComma": "all", + "printWidth": 80 +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..1d02d8c --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# Samvera Static Site Template (featuring Hyku) + +This repo is a [Next.js](https://nextjs.org/) static site project providing information about the Hyku application and ecosystem. It will be a static site that will be deployed on Github Pages. + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +## Deployment + +This site will be deployed on to Github Pages as a static site. To do a local build of the site, run: + +```bash +pnpm build +``` + +## Testing + +This site will be tested using [Playwright](https://playwright.dev/docs). Tests are located in the `tests` directory. To run tests, run: + +```bash +# Run tests in headless mode +pnpm test + +# Run tests in interactive UI mode +pnpm test:ui +``` + +## Code Quality + +To ensure code quality, this site will use ESLint and Prettier. To format project code locally, run: + +```bash +pnpm format +``` diff --git a/next.config.mjs b/next.config.mjs new file mode 100644 index 0000000..bb47cde --- /dev/null +++ b/next.config.mjs @@ -0,0 +1,17 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + assetPrefix: process.env.NEXT_PUBLIC_BASE_PATH, + basePath: process.env.NEXT_PUBLIC_BASE_PATH, + eslint: { + dirs: ["src"], + }, + experimental: { + esmExternals: true, + }, + images: { + unoptimized: true, + }, + output: "export", +}; + +export default nextConfig; diff --git a/package.json b/package.json new file mode 100644 index 0000000..524cff3 --- /dev/null +++ b/package.json @@ -0,0 +1,55 @@ +{ + "name": "avalon-next", + "version": "0.1.0", + "private": true, + "author": [ + "Adam J. Arling ", + "jrgriffiniii " + ], + "license": "MIT", + "scripts": { + "build": "next build", + "deploy": "gh-pages -d out", + "dev": "next dev", + "export": "next export", + "format": "prettier --write .", + "lint": "next lint", + "start": "next start", + "test": "playwright test", + "test:ui": "playwright test --ui" + }, + "dependencies": { + "@contentful/rich-text-react-renderer": "^15.22.1", + "@headlessui/react": "^2.1.1", + "@heroicons/react": "^2.1.4", + "@next/third-parties": "^14.2.4", + "@tailwindcss/forms": "^0.5.7", + "@tanstack/react-query": "^5.49.2", + "contentful": "^10.12.6", + "contentful-management": "^11.27.5", + "install": "^0.13.0", + "next": "14.2.4", + "next-themes": "^0.3.0", + "pnpm": "^9.4.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-feather": "^2.0.10", + "react-loading-skeleton": "^3.4.0" + }, + "devDependencies": { + "@playwright/test": "^1.45.1", + "@tanstack/eslint-plugin-query": "^5.50.0", + "@types/node": "^20.14.9", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "contentful-cli": "^3.3.3", + "eslint": "^9.6.0", + "eslint-config-next": "14.2.4", + "eslint-config-prettier": "^9.1.0", + "gh-pages": "^6.1.1", + "postcss": "^8.4.39", + "prettier": "^3.3.2", + "tailwindcss": "^3.4.4", + "typescript": "^5.5.3" + } +} diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..1c00d74 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,80 @@ +import { defineConfig, devices } from "@playwright/test"; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +const isCI = !!process.env.CI; + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: "./tests", + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: "html", + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: "http://localhost:3000", + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: "on-first-retry", + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: "chromium", + use: { ...devices["Desktop Chrome"] }, + }, + + { + name: "firefox", + use: { ...devices["Desktop Firefox"] }, + }, + + { + name: "webkit", + use: { ...devices["Desktop Safari"] }, + }, + + /* Test against mobile viewports. */ + // { + // name: "Mobile Chrome", + // use: { ...devices["Pixel 5"] }, + // }, + // { + // name: "Mobile Safari", + // use: { ...devices["iPhone 12"] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: isCI ? "npx serve@latest out" : "pnpm run dev", + url: "http://localhost:3000", + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000..1a69fd2 --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,8 @@ +/** @type {import('postcss-load-config').Config} */ +const config = { + plugins: { + tailwindcss: {}, + }, +}; + +export default config; diff --git a/public/app-screenshot.png b/public/app-screenshot.png new file mode 100644 index 0000000..a59c30d Binary files /dev/null and b/public/app-screenshot.png differ diff --git a/public/logo-hyku.png b/public/logo-hyku.png new file mode 100644 index 0000000..1c25d15 Binary files /dev/null and b/public/logo-hyku.png differ diff --git a/src/app/contact/page.tsx b/src/app/contact/page.tsx new file mode 100644 index 0000000..aad5f2e --- /dev/null +++ b/src/app/contact/page.tsx @@ -0,0 +1,78 @@ +import BgLayer from "@/components/layout/bg-layer"; +import ContactCard from "@/components/contact/card"; +import Container from "@/components/layout/container"; +import Header from "@/components/layout/header"; +import MainWrapper from "@/components/layout/main-wrapper"; +import { Metadata } from "next"; + +const contactCards = [ + { + description: + "An open and welcoming forum to find out what is in development for Hyku and to connect with users with similar needs.", + label: "Call Information", + title: "Hyku Interest Group", + url: "https://samvera.atlassian.net/wiki/spaces/samvera/pages/419533203/Samvera+Hyku+Interest+Group", + }, + { + description: "Have a PR to contribute?", + title: "Developers", + url: "https://github.com/samvera/hyku", + }, + { + description: + "Request to join Samvera's slack workspace and join the #hyku channel. Introduce yourself and ask questions!", + email: "", + label: "Slack Information", + title: "Samvera Slack", + url: "https://samvera.atlassian.net/wiki/spaces/samvera/pages/405211682/Getting+Started+in+the+Samvera+Community#Join-the-Samvera-Slack-workspace", + }, + { + description: + "Email Us with questions, requests for demos, and other communications.", + email: "info@samvera.org", + title: "Email", + }, +]; + +export const metadata: Metadata = { + title: "Contact", + description: "Contact the Hyku team", +}; + +export default function ContactPage() { + return ( +
+
+ + + +
+
+
+
+
+

+ Get in touch +

+

+ As part of the Samvera Community, Hyku is driven by the + participation of users and developers. There are many + ways to contribute, collaborate, or just get some + questions answered as you get started with Hyku. +

+
+
+ {contactCards.map((card, index) => ( + + ))} +
+
+
+
+
+
+
+
+
+ ); +} diff --git a/src/app/features/page.tsx b/src/app/features/page.tsx new file mode 100644 index 0000000..8410fd2 --- /dev/null +++ b/src/app/features/page.tsx @@ -0,0 +1,83 @@ +import BgLayer from "@/components/layout/bg-layer"; +import Container from "@/components/layout/container"; +import FeatureList from "@/components/features/list"; +import Header from "@/components/layout/header"; +import Implementations from "@/components/features/implementations"; +import MainWrapper from "@/components/layout/main-wrapper"; +import { Metadata } from "next"; +import PageHeader from "@/components/page-header"; + +export const metadata: Metadata = { + title: "Features and Implementations", +}; + +export default async function FeaturesPage() { + return ( +
+
+ + + + +

Features

+

+ Building on Hyrax, Hyku has a long list of features and + distinctions, including: +

+ +
+
+

Hyku 5.0

+

+ Hyku 5.0 was released in February 2023, offering the ability + to use Solr graph queries to skip having to do nested + indexing. Features include Groups with Roles and the ability + to implement Google or Motomo analytics. +

+
+
+

Hyku 4.0

+

+ Hyku 4.0 was released in May 2022, offering several major new + features including cross-tenant search, three new UI theming + templates that can be implemented from the Admin appearance + dashboard, the ability to make tenants private, to feature + collections, and to support multiple domains per tenant. +

+
+
+

Hyku 3.0

+

+ Hyku 3.0 was released in early 2021, bringing Hyku up to speed + with Hyrax, and introducing new theming and other + configurations. +

+
+
+

Hyku Beta 2.0.0

+

+ Hyku Beta 2.0.0 was released in October 2018 and Hyku was + promoted out of Samvera Labs in February 2019. Information + about the initial Beta Test can be found below and user + documentation is being added to this site regularly. +

+
+

+ Visit the Hyku YouTube Channel for feature demos and the latest + updates. +

+
+ +
+

Implementations

+ +
+
+
+
+
+ ); +} diff --git a/src/app/getting-started/page.tsx b/src/app/getting-started/page.tsx new file mode 100644 index 0000000..baa25d1 --- /dev/null +++ b/src/app/getting-started/page.tsx @@ -0,0 +1,39 @@ +import BgLayer from "@/components/layout/bg-layer"; +import Container from "@/components/layout/container"; +import FaqList from "@/components/faq"; +import GettingStartedList from "@/components/getting-started/list"; +import Header from "@/components/layout/header"; +import HostedSolutions from "@/components/hosted-solutions"; +import MainWrapper from "@/components/layout/main-wrapper"; +import { Metadata } from "next"; +import PageHeader from "@/components/page-header"; + +export const metadata: Metadata = { + title: "Getting Started", +}; + +export default function GettingStartedPage() { + return ( +
+
+ + + + +
+ + +
+

F.A.Q. Frequently Asked Questions

+ +
+
+
+
+
+
+ ); +} diff --git a/src/app/icon.png b/src/app/icon.png new file mode 100644 index 0000000..73ac55b Binary files /dev/null and b/src/app/icon.png differ diff --git a/src/app/layout.tsx b/src/app/layout.tsx new file mode 100644 index 0000000..fdb3b2d --- /dev/null +++ b/src/app/layout.tsx @@ -0,0 +1,42 @@ +import "@/styles/globals.css"; +import "react-loading-skeleton/dist/skeleton.css"; + +import FetchDataWrapper from "@/components/fetch-data-wrapper"; +import Footer from "@/components/layout/footer"; +import { GoogleAnalytics } from "@next/third-parties/google"; +import Header from "@/components/layout/header"; +import type { Metadata } from "next"; +import { Open_Sans } from "next/font/google"; +import { ThemeProvider } from "next-themes"; + +const openSans = Open_Sans({ subsets: ["latin"] }); + +export const metadata: Metadata = { + title: { + template: "%s | Hyku", + default: "Hyku", + }, + description: + "The Next Generation Repository Solution - A Samvera Application", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + + + +
+ {children} +