-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Movie Database DBpedia example (#103)
Resolves #92.
- Loading branch information
1 parent
76830a1
commit 9a52cc3
Showing
30 changed files
with
955 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,3 @@ node_modules | |
|
||
package-lock.json | ||
ontologies | ||
|
||
next-movie-database | ||
react-movie-database |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extends": ["next", "next/core-web-vitals", "prettier"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"editor.formatOnSave": true, | ||
"editor.defaultFormatter": "esbenp.prettier-vscode", | ||
"editor.tabSize": 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Linked Data Movie Database | ||
|
||
This is a IMDb-like movie database based on Linked Data and DBpedia. | ||
|
||
Build with [LDkit](https://ldkit.io), React, TailwindCSS and Next.js. | ||
|
||
## Getting Started | ||
|
||
1. Install dependencies | ||
```bash | ||
npm install | ||
``` | ||
|
||
2. Run the development server: | ||
|
||
```bash | ||
npm run dev | ||
``` | ||
|
||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
@tailwind base; | ||
@tailwind components; | ||
@tailwind utilities; | ||
|
||
:root { | ||
--foreground-rgb: 0, 0, 0; | ||
--background-start-rgb: 255, 255, 255; | ||
--background-end-rgb: 255, 255, 255; | ||
} | ||
|
||
@media (prefers-color-scheme: dark) { | ||
:root { | ||
--foreground-rgb: 255, 255, 255; | ||
--background-start-rgb: 0, 0, 0; | ||
--background-end-rgb: 0, 0, 0; | ||
} | ||
} | ||
|
||
body { | ||
color: rgb(var(--foreground-rgb)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import type { Metadata } from "next"; | ||
import "./globals.css"; | ||
import { Header } from "@/components/Header"; | ||
import { Footer } from "@/components/Footer"; | ||
|
||
export const metadata: Metadata = { | ||
title: "Linked Data Movie Database", | ||
description: "Browse and search movies and actors from Wikidata", | ||
}; | ||
|
||
export default function RootLayout({ | ||
children, | ||
}: { | ||
children: React.ReactNode; | ||
}) { | ||
return ( | ||
<html lang="en" className="bg-black min-h-screen"> | ||
<body className="bg-white"> | ||
<Header /> | ||
<main className="container max-w-6xl mx-auto px-8 py-8 min-h-[80vh]"> | ||
{children} | ||
</main> | ||
<Footer /> | ||
</body> | ||
</html> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { Suspense } from "react"; | ||
|
||
import { | ||
Movies, | ||
MoviesActors, | ||
MoviesDirectors, | ||
MoviesWriters, | ||
MoviesComposers, | ||
} from "@/data/lens"; | ||
import { Thumbnail } from "@/components/Thumbnail"; | ||
import { Links } from "@/components/Links"; | ||
import { Loading } from "@/components/Loading"; | ||
|
||
export default async function MoviePage({ | ||
searchParams, | ||
}: { | ||
searchParams: Record<string, string>; | ||
}) { | ||
const { iri } = searchParams; | ||
|
||
if (!iri || iri.length < 1) { | ||
return <h1>No IRI found!</h1>; | ||
} | ||
|
||
const movie = await Movies.findOne({ | ||
$id: iri, | ||
name: { | ||
$langMatches: "en", | ||
}, | ||
abstract: { | ||
$langMatches: "en", | ||
}, | ||
}); | ||
|
||
if (movie == null) { | ||
return <h1>No movie found!</h1>; | ||
} | ||
|
||
return ( | ||
<div className="grid grid-cols-4 gap-4"> | ||
<article className="prose max-w-full pr-8 col-span-3"> | ||
<h1>{movie.name}</h1> | ||
<p>{movie.abstract}</p> | ||
<h2>Director</h2> | ||
|
||
<Suspense fallback={<Loading />}> | ||
<Director iri={movie.$id} /> | ||
</Suspense> | ||
<h2>Cast</h2> | ||
<Suspense fallback={<Loading />}> | ||
<Cast iri={movie.$id} /> | ||
</Suspense> | ||
<h2>Writer</h2> | ||
<Suspense fallback={<Loading />}> | ||
<Writer iri={movie.$id} /> | ||
</Suspense> | ||
<h2>Composer</h2> | ||
<Suspense fallback={<Loading />}> | ||
<Composer iri={movie.$id} /> | ||
</Suspense> | ||
</article> | ||
<aside className="col-span-1 prose"> | ||
<Thumbnail imageUrl={movie.thumbnail} /> | ||
<Links iri={movie.$id} /> | ||
</aside> | ||
</div> | ||
); | ||
} | ||
|
||
async function Director({ iri }: { iri: string }) { | ||
const movieWithDirectors = await MoviesDirectors.findByIri(iri); | ||
return <PersonList>{movieWithDirectors?.directors}</PersonList>; | ||
} | ||
|
||
async function Writer({ iri }: { iri: string }) { | ||
const movieWithWriters = await MoviesWriters.findByIri(iri); | ||
return <PersonList>{movieWithWriters?.writers}</PersonList>; | ||
} | ||
|
||
async function Composer({ iri }: { iri: string }) { | ||
const movieWithComposers = await MoviesComposers.findByIri(iri); | ||
return <PersonList>{movieWithComposers?.composers}</PersonList>; | ||
} | ||
|
||
async function Cast({ iri }: { iri: string }) { | ||
const movieWithActors = await MoviesActors.findByIri(iri); | ||
return <PersonList>{movieWithActors?.starring}</PersonList>; | ||
} | ||
|
||
function PersonList({ | ||
children, | ||
}: { | ||
children: { $id: string; name: string }[] | undefined; | ||
}) { | ||
if (children === undefined || children.length < 1) { | ||
return <p>No records found.</p>; | ||
} | ||
|
||
return ( | ||
<ul> | ||
{children.map((person) => ( | ||
<li key={person.$id}> | ||
<a href={`/person?iri=${person.$id}`}>{person.name}</a> | ||
</li> | ||
))} | ||
</ul> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import { Loading } from "@/components/Loading"; | ||
import { Search, SearchInterface } from "@/data/lens"; | ||
import { yago } from "@/data/namespaces"; | ||
import { schema } from "ldkit/namespaces"; | ||
import { Suspense } from "react"; | ||
|
||
export default function Home() { | ||
return ( | ||
<> | ||
<p className="text-center text-lg pb-8 pt-2"> | ||
Use the search bar above to look for people or movies, or pick some | ||
selection below. | ||
</p> | ||
<div className="grid grid-cols-3"> | ||
<section className="prose"> | ||
<h1>Top Movies</h1> | ||
<Suspense fallback={<Loading />}> | ||
<TopMovies /> | ||
</Suspense> | ||
</section> | ||
<section className="prose"> | ||
<h1>Top Actors</h1> | ||
<Suspense fallback={<Loading />}> | ||
<TopActors /> | ||
</Suspense> | ||
</section> | ||
<section className="prose"> | ||
<h1>Top Directors</h1> | ||
<Suspense fallback={<Loading />}> | ||
<TopDirectors /> | ||
</Suspense> | ||
</section> | ||
</div> | ||
</> | ||
); | ||
} | ||
|
||
async function TopMovies() { | ||
const movies = await search( | ||
[ | ||
"http://dbpedia.org/resource/The_Shawshank_Redemption", | ||
"http://dbpedia.org/resource/The_Godfather", | ||
"http://dbpedia.org/resource/The_Dark_Knight", | ||
"http://dbpedia.org/resource/Pulp_Fiction", | ||
"http://dbpedia.org/resource/Schindler's_List", | ||
"http://dbpedia.org/resource/The_Matrix", | ||
"http://dbpedia.org/resource/Fight_Club", | ||
"http://dbpedia.org/resource/Goodfellas", | ||
"http://dbpedia.org/resource/Terminator_2:_Judgment_Day", | ||
"http://dbpedia.org/resource/Inception", | ||
], | ||
schema.Movie | ||
); | ||
return <SearchResults items={movies} />; | ||
} | ||
|
||
async function TopActors() { | ||
const movies = await search( | ||
[ | ||
"http://dbpedia.org/resource/Christian_Bale", | ||
"http://dbpedia.org/resource/Helena_Bonham_Carter", | ||
"http://dbpedia.org/resource/Robert_De_Niro", | ||
"http://dbpedia.org/resource/Al_Pacino", | ||
"http://dbpedia.org/resource/Tom_Hanks", | ||
"http://dbpedia.org/resource/Leonardo_DiCaprio", | ||
"http://dbpedia.org/resource/Meryl_Streep", | ||
"http://dbpedia.org/resource/Brad_Pitt", | ||
"http://dbpedia.org/resource/Tom_Cruise", | ||
"http://dbpedia.org/resource/Sigourney_Weaver", | ||
], | ||
yago.Actor109765278 | ||
); | ||
return <SearchResults items={movies} />; | ||
} | ||
|
||
async function TopDirectors() { | ||
const movies = await search( | ||
[ | ||
"http://dbpedia.org/resource/Stanley_Kubrick", | ||
"http://dbpedia.org/resource/Quentin_Tarantino", | ||
"http://dbpedia.org/resource/Christopher_Nolan", | ||
"http://dbpedia.org/resource/Ridley_Scott", | ||
"http://dbpedia.org/resource/Steven_Spielberg", | ||
"http://dbpedia.org/resource/Martin_Scorsese", | ||
"http://dbpedia.org/resource/Alfred_Hitchcock", | ||
"http://dbpedia.org/resource/David_Fincher", | ||
"http://dbpedia.org/resource/Tim_Burton", | ||
"http://dbpedia.org/resource/Guillermo_del_Toro", | ||
], | ||
yago.Director110014939 | ||
); | ||
return <SearchResults items={movies} />; | ||
} | ||
|
||
function SearchResults({ items }: { items: SearchInterface[] }) { | ||
return ( | ||
<ul> | ||
{items.map((x) => ( | ||
<SearchResult key={x.$id} {...x} /> | ||
))} | ||
</ul> | ||
); | ||
} | ||
|
||
function SearchResult(props: SearchInterface) { | ||
const mode = props.types.includes(schema.Movie) ? "movie" : "person"; | ||
|
||
return ( | ||
<li> | ||
<a href={`/${mode}?iri=${props.$id}`}>{props.name}</a> | ||
</li> | ||
); | ||
} | ||
|
||
async function search(ids: string[], type: string) { | ||
return Search.find({ | ||
where: { | ||
$id: ids, | ||
name: { | ||
$langMatches: "en", | ||
}, | ||
types: { | ||
$in: [type], | ||
}, | ||
}, | ||
}); | ||
} |
Oops, something went wrong.