├── .nvmrc ├── .prettierignore ├── public ├── _redirects ├── robots.txt ├── icons │ ├── favicon.png │ ├── icon-72x72.png │ ├── icon-96x96.png │ ├── icon-128x128.png │ ├── icon-144x144.png │ ├── icon-152x152.png │ ├── icon-192x192.png │ ├── icon-384x384.png │ ├── icon-512x512.png │ └── apple-touch-icon-precomposed.png ├── images │ ├── 0gedy9.webp │ ├── 0u1y5h.webp │ ├── 0xvaj.webp │ ├── 13c6tp.webp │ ├── 182sy.webp │ ├── 1c5ju.webp │ ├── 1p78p9.webp │ ├── 2iplvu.webp │ ├── 2m01sf.webp │ ├── 32w4ju.webp │ ├── 3blyco.webp │ ├── 4efexc.webp │ ├── 4i903l.webp │ ├── 4ikhh.webp │ ├── 4sdmwk.webp │ ├── 4st05.webp │ ├── 58g4wh.webp │ ├── 59twfm.webp │ ├── 5mvoqc.webp │ ├── 5wu0vm.webp │ ├── 6aj2yl.webp │ ├── 6nhip.webp │ ├── 6vh8m.webp │ ├── 7svst.webp │ ├── 82jm6a.webp │ ├── 843opg.webp │ ├── 8kxa4d.webp │ ├── 8r6ysg.webp │ ├── 8rusl9.webp │ ├── 9ubka7.webp │ ├── a3ptwo.webp │ ├── a819ci.webp │ ├── a8buj2.webp │ ├── ayz3em.webp │ ├── c0tacc.webp │ ├── cl1fqt.webp │ ├── d9wmm.webp │ ├── dlbb9.webp │ ├── dre3v.webp │ ├── dulv1e.webp │ ├── dwrwgc.webp │ ├── dygp3m.webp │ ├── f8378.webp │ ├── fg50dg.webp │ ├── fg8wvd.webp │ ├── fwf5r.webp │ ├── gl2xwd.webp │ ├── gnn16q.webp │ ├── gojt1l.webp │ ├── hbomll.webp │ ├── hm9uvl.webp │ ├── hrlye4.webp │ ├── hrti5f.webp │ ├── i98pmq.webp │ ├── ibdzo.webp │ ├── ifkwk4.webp │ ├── iw2ka.webp │ ├── jrx1x7.webp │ ├── k7mc09.webp │ ├── k8zceg.webp │ ├── krog0u.webp │ ├── l57v9n.webp │ ├── lo3ekv.webp │ ├── m0z5s.webp │ ├── mola09.webp │ ├── nffz.webp │ ├── njx3o6.webp │ ├── nv2mfi.webp │ ├── o7nx1m.webp │ ├── ojfkg9.webp │ ├── p0h6n.webp │ ├── pzxph6.webp │ ├── q7lag.webp │ ├── q866h.webp │ ├── q94duq.webp │ ├── r5edra.webp │ ├── r66ti9.webp │ ├── rgmrc.webp │ ├── rhth3d.webp │ ├── rxfw3j.webp │ ├── s0e7cf.webp │ ├── s2yo4.webp │ ├── snjnu7.webp │ ├── tfiuor.webp │ ├── uu18ws.webp │ ├── vaahds.webp │ ├── w3wqr7.webp │ ├── w6pe0e.webp │ ├── wfar98.webp │ ├── wfwtpc.webp │ ├── wnb3ed.webp │ ├── xaiuc.webp │ ├── xhk01d.webp │ ├── xmtnkw.webp │ ├── xwu69d.webp │ ├── xx5l0r.webp │ ├── yethsn.webp │ ├── yt4twm.webp │ ├── ytwzjb.webp │ ├── zkjzj.webp │ ├── zoc8nc.webp │ ├── zpdazf.webp │ ├── zwfhpe.webp │ ├── 123ad0p.webp │ ├── 8h6x7wd.webp │ ├── ckbp6vy.webp │ ├── w81dtub.webp │ └── meta-screenshot.jpg ├── Fredoka-SemiBold.ttf ├── _headers ├── data │ ├── ntnu │ │ ├── tdt4160 │ │ │ ├── Age of Computers: England.json │ │ │ ├── Age of Computers: Assemblyprogrammering.json │ │ │ ├── Age of Computers: Eksempler, prosessorer.json │ │ │ ├── Age of Computers: Faktaspørsmål.json │ │ │ ├── Eksamen 2007 Kont.json │ │ │ ├── Age of Computers: Digitalteknikk.json │ │ │ ├── Eksamen 2009 Høst.json │ │ │ ├── Eksamen 2009 Kont.json │ │ │ ├── Eksamen 2008 Høst.json │ │ │ ├── Age of Computers: Primærlager.json │ │ │ ├── Age of Computers: Tallsystemer.json │ │ │ ├── Age of Computers: Teoretikerne.json │ │ │ ├── Age of Computers: Beregninger.json │ │ │ ├── Age of Computers: Historiespørsmål.json │ │ │ ├── Age of Computers: Prosessorens oppbygning.json │ │ │ └── Age of Computers: Samlebånd.json │ │ ├── tdt4240 │ │ │ ├── 2015 Kahoot 18: Patterns and Tactics.json │ │ │ ├── 2015 Kahoot 16: CBAM.json │ │ │ ├── 2015 Kahoot 09: Design patterns II.json │ │ │ ├── 2015 Kahoot 02: Structures and Views.json │ │ │ ├── 2015 Kahoot 01: Introduction.json │ │ │ ├── 2015 Kahoot 05: Influences.json │ │ │ ├── 2015 Kahoot 23: Cloud.json │ │ │ ├── 2015 Kahoot 21: Software Product Line.json │ │ │ ├── 2015 Kahoot 08: Design patterns.json │ │ │ ├── 2015 Kahoot 03: Architectural Patterns Intro.json │ │ │ ├── 2015 Kahoot 12: Modeling and Analysis II.json │ │ │ ├── 2015 Kahoot 22: Edge.json │ │ │ ├── 2015 Kahoot 06: Requirements and Quality Attributes.json │ │ │ ├── 2015 Kahoot 14: Evaluation.json │ │ │ ├── 2015 Kahoot 20: Implementation and Testing.json │ │ │ ├── 2015 Kahoot 13: 4+1 View Model.json │ │ │ ├── 2015 Kahoot 11: Modeling and Analysis.json │ │ │ ├── 2015 Kahoot 10: Architectural Patterns.json │ │ │ ├── 2015 Kahoot 04: Life Cycle.json │ │ │ ├── 2015 Kahoot 19: Requirements.json │ │ │ └── 2015 Kahoot 15: Evaluation + ATAM.json │ │ ├── mfel1050 │ │ │ └── 2006 Høst.json │ │ ├── tdt4117 │ │ │ ├── 2007 Vår.json │ │ │ ├── 2009 Vår.json │ │ │ └── 2013 Høst.json │ │ ├── tdt4136 │ │ │ ├── 2012 Fall.json │ │ │ ├── 2016 Fall.json │ │ │ ├── 2014 Continuation Exam.json │ │ │ ├── 2013 Fall.json │ │ │ └── 2014 Fall.json │ │ └── tdt4171 │ │ │ └── 2015 Spring.json │ └── oslomet │ │ └── syba1010 │ │ ├── Sansene.json │ │ ├── Fordøyelsessystemet.json │ │ ├── Nervesystemet.json │ │ ├── Muskler og skjelett.json │ │ ├── Nyrer og urinveier.json │ │ ├── Respirasjonssystemet.json │ │ ├── Celler og vev.json │ │ ├── Reproduksjon.json │ │ └── Sirkulasjonssystemet.json └── manifest.json ├── statichost.yml ├── src ├── components │ ├── LoadingSpinner │ │ ├── index.tsx │ │ └── LoadingSpinner.module.css │ ├── index.ts │ ├── Buttons │ │ ├── CategoryButton │ │ │ ├── CategoryButton.module.css │ │ │ └── index.tsx │ │ ├── ResultButton │ │ │ ├── ResultButton.module.css │ │ │ └── index.tsx │ │ ├── StandardButton │ │ │ ├── StandardButton.module.css │ │ │ └── index.tsx │ │ ├── BaseButton.module.css │ │ ├── Alternative │ │ │ ├── index.tsx │ │ │ └── Alternative.module.css │ │ └── BaseButton.tsx │ ├── DivChart │ │ ├── index.tsx │ │ └── DivChart.module.css │ ├── Jumbotron │ │ ├── Jumbotron.module.css │ │ └── index.tsx │ ├── Navbar │ │ ├── index.tsx │ │ └── Navbar.module.css │ ├── ProgressBar │ │ ├── index.tsx │ │ └── ProgressBar.module.css │ └── Kitem │ │ ├── index.tsx │ │ └── Kitem.module.css ├── schools.json ├── containers │ ├── Questions │ │ ├── Question │ │ │ ├── Question.module.css │ │ │ └── index.tsx │ │ └── Questions.module.css │ ├── Result │ │ ├── Result.module.css │ │ └── index.tsx │ ├── About │ │ ├── About.module.css │ │ └── index.tsx │ ├── AppContainer.tsx │ ├── Schools │ │ ├── Schools.module.css │ │ └── index.tsx │ ├── Courses │ │ ├── Courses.module.css │ │ └── index.tsx │ └── Exams │ │ ├── Exams.module.css │ │ └── index.tsx ├── interfaces.ts ├── base-styles │ ├── typography.css │ ├── main.css │ └── colors.css ├── main.tsx ├── hooks │ └── contexts.ts ├── utils │ └── index.ts ├── routes.tsx ├── api │ └── index.ts └── courses.json ├── tsconfig.node.json ├── .gitignore ├── .stylelintrc ├── README.md ├── .github └── workflows │ ├── build-and-test.yml │ └── codeql-analysis.yml ├── LICENSE.md ├── tsconfig.json ├── eslint.config.js ├── package.json ├── vite.config.ts └── index.html /.nvmrc: -------------------------------------------------------------------------------- 1 | 22 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | functions/lib 3 | -------------------------------------------------------------------------------- /public/_redirects: -------------------------------------------------------------------------------- 1 | /* /index.html 200 2 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | -------------------------------------------------------------------------------- /statichost.yml: -------------------------------------------------------------------------------- 1 | domains: 2 | - kramster.it 3 | -------------------------------------------------------------------------------- /public/icons/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/icons/favicon.png -------------------------------------------------------------------------------- /public/images/0gedy9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/0gedy9.webp -------------------------------------------------------------------------------- /public/images/0u1y5h.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/0u1y5h.webp -------------------------------------------------------------------------------- /public/images/0xvaj.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/0xvaj.webp -------------------------------------------------------------------------------- /public/images/13c6tp.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/13c6tp.webp -------------------------------------------------------------------------------- /public/images/182sy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/182sy.webp -------------------------------------------------------------------------------- /public/images/1c5ju.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/1c5ju.webp -------------------------------------------------------------------------------- /public/images/1p78p9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/1p78p9.webp -------------------------------------------------------------------------------- /public/images/2iplvu.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/2iplvu.webp -------------------------------------------------------------------------------- /public/images/2m01sf.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/2m01sf.webp -------------------------------------------------------------------------------- /public/images/32w4ju.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/32w4ju.webp -------------------------------------------------------------------------------- /public/images/3blyco.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/3blyco.webp -------------------------------------------------------------------------------- /public/images/4efexc.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/4efexc.webp -------------------------------------------------------------------------------- /public/images/4i903l.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/4i903l.webp -------------------------------------------------------------------------------- /public/images/4ikhh.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/4ikhh.webp -------------------------------------------------------------------------------- /public/images/4sdmwk.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/4sdmwk.webp -------------------------------------------------------------------------------- /public/images/4st05.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/4st05.webp -------------------------------------------------------------------------------- /public/images/58g4wh.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/58g4wh.webp -------------------------------------------------------------------------------- /public/images/59twfm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/59twfm.webp -------------------------------------------------------------------------------- /public/images/5mvoqc.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/5mvoqc.webp -------------------------------------------------------------------------------- /public/images/5wu0vm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/5wu0vm.webp -------------------------------------------------------------------------------- /public/images/6aj2yl.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/6aj2yl.webp -------------------------------------------------------------------------------- /public/images/6nhip.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/6nhip.webp -------------------------------------------------------------------------------- /public/images/6vh8m.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/6vh8m.webp -------------------------------------------------------------------------------- /public/images/7svst.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/7svst.webp -------------------------------------------------------------------------------- /public/images/82jm6a.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/82jm6a.webp -------------------------------------------------------------------------------- /public/images/843opg.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/843opg.webp -------------------------------------------------------------------------------- /public/images/8kxa4d.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/8kxa4d.webp -------------------------------------------------------------------------------- /public/images/8r6ysg.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/8r6ysg.webp -------------------------------------------------------------------------------- /public/images/8rusl9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/8rusl9.webp -------------------------------------------------------------------------------- /public/images/9ubka7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/9ubka7.webp -------------------------------------------------------------------------------- /public/images/a3ptwo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/a3ptwo.webp -------------------------------------------------------------------------------- /public/images/a819ci.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/a819ci.webp -------------------------------------------------------------------------------- /public/images/a8buj2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/a8buj2.webp -------------------------------------------------------------------------------- /public/images/ayz3em.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/ayz3em.webp -------------------------------------------------------------------------------- /public/images/c0tacc.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/c0tacc.webp -------------------------------------------------------------------------------- /public/images/cl1fqt.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/cl1fqt.webp -------------------------------------------------------------------------------- /public/images/d9wmm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/d9wmm.webp -------------------------------------------------------------------------------- /public/images/dlbb9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/dlbb9.webp -------------------------------------------------------------------------------- /public/images/dre3v.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/dre3v.webp -------------------------------------------------------------------------------- /public/images/dulv1e.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/dulv1e.webp -------------------------------------------------------------------------------- /public/images/dwrwgc.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/dwrwgc.webp -------------------------------------------------------------------------------- /public/images/dygp3m.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/dygp3m.webp -------------------------------------------------------------------------------- /public/images/f8378.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/f8378.webp -------------------------------------------------------------------------------- /public/images/fg50dg.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/fg50dg.webp -------------------------------------------------------------------------------- /public/images/fg8wvd.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/fg8wvd.webp -------------------------------------------------------------------------------- /public/images/fwf5r.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/fwf5r.webp -------------------------------------------------------------------------------- /public/images/gl2xwd.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/gl2xwd.webp -------------------------------------------------------------------------------- /public/images/gnn16q.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/gnn16q.webp -------------------------------------------------------------------------------- /public/images/gojt1l.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/gojt1l.webp -------------------------------------------------------------------------------- /public/images/hbomll.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/hbomll.webp -------------------------------------------------------------------------------- /public/images/hm9uvl.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/hm9uvl.webp -------------------------------------------------------------------------------- /public/images/hrlye4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/hrlye4.webp -------------------------------------------------------------------------------- /public/images/hrti5f.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/hrti5f.webp -------------------------------------------------------------------------------- /public/images/i98pmq.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/i98pmq.webp -------------------------------------------------------------------------------- /public/images/ibdzo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/ibdzo.webp -------------------------------------------------------------------------------- /public/images/ifkwk4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/ifkwk4.webp -------------------------------------------------------------------------------- /public/images/iw2ka.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/iw2ka.webp -------------------------------------------------------------------------------- /public/images/jrx1x7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/jrx1x7.webp -------------------------------------------------------------------------------- /public/images/k7mc09.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/k7mc09.webp -------------------------------------------------------------------------------- /public/images/k8zceg.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/k8zceg.webp -------------------------------------------------------------------------------- /public/images/krog0u.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/krog0u.webp -------------------------------------------------------------------------------- /public/images/l57v9n.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/l57v9n.webp -------------------------------------------------------------------------------- /public/images/lo3ekv.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/lo3ekv.webp -------------------------------------------------------------------------------- /public/images/m0z5s.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/m0z5s.webp -------------------------------------------------------------------------------- /public/images/mola09.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/mola09.webp -------------------------------------------------------------------------------- /public/images/nffz.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/nffz.webp -------------------------------------------------------------------------------- /public/images/njx3o6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/njx3o6.webp -------------------------------------------------------------------------------- /public/images/nv2mfi.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/nv2mfi.webp -------------------------------------------------------------------------------- /public/images/o7nx1m.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/o7nx1m.webp -------------------------------------------------------------------------------- /public/images/ojfkg9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/ojfkg9.webp -------------------------------------------------------------------------------- /public/images/p0h6n.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/p0h6n.webp -------------------------------------------------------------------------------- /public/images/pzxph6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/pzxph6.webp -------------------------------------------------------------------------------- /public/images/q7lag.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/q7lag.webp -------------------------------------------------------------------------------- /public/images/q866h.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/q866h.webp -------------------------------------------------------------------------------- /public/images/q94duq.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/q94duq.webp -------------------------------------------------------------------------------- /public/images/r5edra.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/r5edra.webp -------------------------------------------------------------------------------- /public/images/r66ti9.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/r66ti9.webp -------------------------------------------------------------------------------- /public/images/rgmrc.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/rgmrc.webp -------------------------------------------------------------------------------- /public/images/rhth3d.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/rhth3d.webp -------------------------------------------------------------------------------- /public/images/rxfw3j.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/rxfw3j.webp -------------------------------------------------------------------------------- /public/images/s0e7cf.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/s0e7cf.webp -------------------------------------------------------------------------------- /public/images/s2yo4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/s2yo4.webp -------------------------------------------------------------------------------- /public/images/snjnu7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/snjnu7.webp -------------------------------------------------------------------------------- /public/images/tfiuor.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/tfiuor.webp -------------------------------------------------------------------------------- /public/images/uu18ws.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/uu18ws.webp -------------------------------------------------------------------------------- /public/images/vaahds.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/vaahds.webp -------------------------------------------------------------------------------- /public/images/w3wqr7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/w3wqr7.webp -------------------------------------------------------------------------------- /public/images/w6pe0e.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/w6pe0e.webp -------------------------------------------------------------------------------- /public/images/wfar98.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/wfar98.webp -------------------------------------------------------------------------------- /public/images/wfwtpc.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/wfwtpc.webp -------------------------------------------------------------------------------- /public/images/wnb3ed.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/wnb3ed.webp -------------------------------------------------------------------------------- /public/images/xaiuc.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/xaiuc.webp -------------------------------------------------------------------------------- /public/images/xhk01d.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/xhk01d.webp -------------------------------------------------------------------------------- /public/images/xmtnkw.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/xmtnkw.webp -------------------------------------------------------------------------------- /public/images/xwu69d.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/xwu69d.webp -------------------------------------------------------------------------------- /public/images/xx5l0r.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/xx5l0r.webp -------------------------------------------------------------------------------- /public/images/yethsn.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/yethsn.webp -------------------------------------------------------------------------------- /public/images/yt4twm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/yt4twm.webp -------------------------------------------------------------------------------- /public/images/ytwzjb.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/ytwzjb.webp -------------------------------------------------------------------------------- /public/images/zkjzj.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/zkjzj.webp -------------------------------------------------------------------------------- /public/images/zoc8nc.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/zoc8nc.webp -------------------------------------------------------------------------------- /public/images/zpdazf.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/zpdazf.webp -------------------------------------------------------------------------------- /public/images/zwfhpe.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/zwfhpe.webp -------------------------------------------------------------------------------- /public/Fredoka-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/Fredoka-SemiBold.ttf -------------------------------------------------------------------------------- /public/icons/icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/icons/icon-72x72.png -------------------------------------------------------------------------------- /public/icons/icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/icons/icon-96x96.png -------------------------------------------------------------------------------- /public/images/123ad0p.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/123ad0p.webp -------------------------------------------------------------------------------- /public/images/8h6x7wd.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/8h6x7wd.webp -------------------------------------------------------------------------------- /public/images/ckbp6vy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/ckbp6vy.webp -------------------------------------------------------------------------------- /public/images/w81dtub.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/w81dtub.webp -------------------------------------------------------------------------------- /public/icons/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/icons/icon-128x128.png -------------------------------------------------------------------------------- /public/icons/icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/icons/icon-144x144.png -------------------------------------------------------------------------------- /public/icons/icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/icons/icon-152x152.png -------------------------------------------------------------------------------- /public/icons/icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/icons/icon-192x192.png -------------------------------------------------------------------------------- /public/icons/icon-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/icons/icon-384x384.png -------------------------------------------------------------------------------- /public/icons/icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/icons/icon-512x512.png -------------------------------------------------------------------------------- /public/images/meta-screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/images/meta-screenshot.jpg -------------------------------------------------------------------------------- /public/icons/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draperunner/kramster/master/public/icons/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /src/components/LoadingSpinner/index.tsx: -------------------------------------------------------------------------------- 1 | import styles from "./LoadingSpinner.module.css"; 2 | 3 | const LoadingSpinner = () =>
; 4 | 5 | export default LoadingSpinner; 6 | -------------------------------------------------------------------------------- /src/schools.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "abbreviation": "NTNU", 4 | "name": "Norges teknisk-naturvitenskapelige universitet" 5 | }, 6 | { 7 | "abbreviation": "OsloMet", 8 | "name": "Storbyuniversitetet" 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /src/containers/Questions/Question/Question.module.css: -------------------------------------------------------------------------------- 1 | .question { 2 | margin: 0; 3 | font-size: 1.5rem; 4 | font-weight: 500; 5 | font-family: var(--font-body); 6 | } 7 | 8 | @media (max-width: 767px) { 9 | .question { 10 | font-size: 1rem; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/components/index.ts: -------------------------------------------------------------------------------- 1 | export { default as ProgressBar } from "./ProgressBar"; 2 | export { default as Navbar } from "./Navbar"; 3 | export { default as LoadingSpinner } from "./LoadingSpinner"; 4 | export { default as Kitem } from "./Kitem"; 5 | export { default as Jumbotron } from "./Jumbotron"; 6 | -------------------------------------------------------------------------------- /src/interfaces.ts: -------------------------------------------------------------------------------- 1 | export type Grade = "A" | "B" | "C" | "D" | "E" | "F"; 2 | 3 | export interface Question { 4 | question: string; 5 | options: string[]; 6 | answers: number[]; 7 | } 8 | 9 | export interface HistoryEntry { 10 | givenAnswer: string; 11 | wasCorrect: boolean; 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true, 8 | "strict": true 9 | }, 10 | "include": ["vite.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ 3 | bower_components/ 4 | dist/ 5 | dev-dist 6 | *.annotated.js 7 | src/client/scripts.min.js 8 | src/client/styles.min.css 9 | doc/ 10 | *.iml 11 | .DS_Store 12 | *.sh 13 | !deploy*.sh 14 | *.bson 15 | *.metadata.json 16 | *.tar.gz 17 | .firebase/ 18 | *.log 19 | -------------------------------------------------------------------------------- /src/base-styles/typography.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --font-header: fredoka, "Arial Rounded MT Bold", sans-serif; 3 | --font-body: verdana, tahoma, arial, helvetica, sans-serif; 4 | } 5 | 6 | @font-face { 7 | font-family: fredoka; 8 | src: url("/Fredoka-SemiBold.ttf"); 9 | font-display: swap; 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Buttons/CategoryButton/CategoryButton.module.css: -------------------------------------------------------------------------------- 1 | .category { 2 | composes: base from "../BaseButton.module.css"; 3 | color: black; 4 | background-color: var(--yellow); 5 | font-family: var(--font-header); 6 | text-transform: uppercase; 7 | 8 | &:hover { 9 | filter: brightness(110%); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from "react-dom/client"; 2 | 3 | import "./base-styles/colors.css"; 4 | import "./base-styles/typography.css"; 5 | import "./base-styles/main.css"; 6 | 7 | import Routes from "./routes"; 8 | 9 | const element = document.getElementById("app"); 10 | if (element) { 11 | createRoot(element).render(); 12 | } 13 | -------------------------------------------------------------------------------- /src/components/Buttons/ResultButton/ResultButton.module.css: -------------------------------------------------------------------------------- 1 | .result { 2 | composes: base from "../BaseButton.module.css"; 3 | background-color: var(--green); 4 | padding: 8px; 5 | color: black; 6 | 7 | &:hover { 8 | background-color: var(--green-light); 9 | } 10 | } 11 | 12 | .result { 13 | padding: 10px; 14 | font-family: var(--font-header); 15 | } 16 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "rules": { 4 | "property-no-unknown": [true, { "ignoreProperties": ["composes"] }], 5 | "selector-class-pattern": null, 6 | "selector-pseudo-class-no-unknown": null, 7 | "value-keyword-case": [ 8 | "lower", 9 | { "ignoreProperties": ["composes", "font-family"] } 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/containers/Questions/Question/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC } from "react"; 2 | import { sanitize } from "../../../utils"; 3 | import styles from "./Question.module.css"; 4 | 5 | interface Props { 6 | text: string; 7 | } 8 | 9 | const Question: FC = (props) => ( 10 |

14 | ); 15 | 16 | export default Question; 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kramster! 2 | 3 | See it live here: [kramster.it](https://kramster.it) 4 | 5 | Kramster is a quiz app for making exam preparation more fun. It works for all exams having multiple choice questions. 6 | 7 | ## Development 8 | 9 | Install the dependencies: 10 | 11 | ``` 12 | npm install 13 | ``` 14 | 15 | Start the frontend app: 16 | 17 | ``` 18 | npm start 19 | ``` 20 | 21 | Then open http://localhost:5173 and get going. 22 | -------------------------------------------------------------------------------- /src/containers/Result/Result.module.css: -------------------------------------------------------------------------------- 1 | .header { 2 | font-family: var(--font-header); 3 | font-size: 36px; 4 | font-weight: 500; 5 | margin: 10px 0 0; 6 | } 7 | 8 | .row { 9 | display: flex; 10 | justify-content: space-around; 11 | gap: 16px; 12 | margin-top: 16px; 13 | } 14 | 15 | .row > div { 16 | flex: 1; 17 | } 18 | 19 | .buttons { 20 | display: flex; 21 | flex-direction: row; 22 | margin-top: 32px; 23 | gap: 8px; 24 | } 25 | -------------------------------------------------------------------------------- /src/hooks/contexts.ts: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from "react"; 2 | 3 | import { HistoryEntry } from "../interfaces"; 4 | 5 | type HistorySetter = React.Dispatch>; 6 | 7 | export const HistoryContext = createContext<[HistoryEntry[], HistorySetter]>([ 8 | [], 9 | (): void => {}, 10 | ]); 11 | 12 | export function useHistory(): [HistoryEntry[], HistorySetter] { 13 | return useContext(HistoryContext); 14 | } 15 | -------------------------------------------------------------------------------- /.github/workflows/build-and-test.yml: -------------------------------------------------------------------------------- 1 | name: Build and test 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Install dependencies 17 | run: npm ci 18 | 19 | - name: Check types 20 | run: npm run ts 21 | 22 | - name: Lint 23 | run: npm run lint 24 | -------------------------------------------------------------------------------- /src/components/Buttons/StandardButton/StandardButton.module.css: -------------------------------------------------------------------------------- 1 | .hyphenate { 2 | overflow-wrap: break-word; 3 | word-wrap: break-word; 4 | -webkit-hyphens: auto; 5 | -ms-hyphens: auto; 6 | -moz-hyphens: auto; 7 | hyphens: auto; 8 | } 9 | 10 | .standard { 11 | composes: base from "../BaseButton.module.css"; 12 | composes: hyphenate; 13 | background-color: var(--blue); 14 | color: white; 15 | 16 | &:hover { 17 | background-color: var(--blue-light); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/components/Buttons/BaseButton.module.css: -------------------------------------------------------------------------------- 1 | .base { 2 | white-space: normal; 3 | letter-spacing: 1px; 4 | border-radius: 0.5rem; 5 | border: none; 6 | transition: all 0.2s; 7 | padding: 20px; 8 | display: block; 9 | text-align: center; 10 | text-decoration: none !important; 11 | cursor: pointer; 12 | 13 | &:focus { 14 | outline: 2px solid var(--brand-color); 15 | } 16 | } 17 | 18 | @media (max-width: 767px) { 19 | .base { 20 | font-size: 14px; 21 | padding: 12px; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/containers/Questions/Questions.module.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | margin: 0; 3 | } 4 | 5 | .questionRow { 6 | margin: 40px 0; 7 | } 8 | 9 | .alternatives, 10 | .explanationRow { 11 | margin: 20px 0; 12 | } 13 | 14 | .alternatives { 15 | display: flex; 16 | flex-direction: column; 17 | gap: 8px; 18 | 19 | > button { 20 | width: fit-content; 21 | } 22 | } 23 | 24 | .continueTip { 25 | color: var(--brand-color); 26 | display: block; 27 | margin: 3px; 28 | } 29 | 30 | @media (max-width: 767px) { 31 | .wrapper h1 { 32 | font-size: 1rem; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2017 Mats Byrkjeland 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /src/containers/About/About.module.css: -------------------------------------------------------------------------------- 1 | .about { 2 | padding: 0 80px; 3 | margin-bottom: 40px; 4 | } 5 | 6 | .title { 7 | color: var(--brand-color); 8 | font-family: var(--font-header); 9 | letter-spacing: 2px; 10 | line-height: 40px; 11 | font-size: 63px; 12 | font-weight: 500; 13 | } 14 | 15 | .intro { 16 | font-size: 21px; 17 | font-weight: 500; 18 | } 19 | 20 | @media (max-width: 767px) { 21 | .about { 22 | padding: 0 8px; 23 | margin-bottom: 10px; 24 | } 25 | 26 | .title { 27 | line-height: 40px; 28 | font-size: 36px; 29 | font-weight: 500; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/components/Buttons/ResultButton/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC, ReactNode } from "react"; 2 | import BaseButton from "../BaseButton"; 3 | import styles from "./ResultButton.module.css"; 4 | 5 | interface Props { 6 | href: string; 7 | onClick?: ( 8 | event: 9 | | React.KeyboardEvent 10 | | React.MouseEvent, 11 | ) => void; 12 | children?: ReactNode; 13 | } 14 | 15 | const ResultButton: FC = (props) => ( 16 | 17 | {props.children} 18 | 19 | ); 20 | 21 | export default ResultButton; 22 | -------------------------------------------------------------------------------- /src/components/Buttons/CategoryButton/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC, ReactNode } from "react"; 2 | import BaseButton from "../BaseButton"; 3 | import styles from "./CategoryButton.module.css"; 4 | 5 | interface Props { 6 | href: string; 7 | onClick?: ( 8 | event: 9 | | React.KeyboardEvent 10 | | React.MouseEvent, 11 | ) => void; 12 | children?: ReactNode; 13 | } 14 | 15 | const CategoryButton: FC = (props) => ( 16 | 17 | {props.children} 18 | 19 | ); 20 | 21 | export default CategoryButton; 22 | -------------------------------------------------------------------------------- /src/components/Buttons/StandardButton/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC, ReactNode } from "react"; 2 | import BaseButton from "../BaseButton"; 3 | import styles from "./StandardButton.module.css"; 4 | 5 | interface Props { 6 | href: string; 7 | onClick?: ( 8 | event: 9 | | React.KeyboardEvent 10 | | React.MouseEvent, 11 | ) => void; 12 | children?: ReactNode; 13 | } 14 | 15 | const StandardButton: FC = (props) => ( 16 | 17 | {props.children} 18 | 19 | ); 20 | 21 | export default StandardButton; 22 | -------------------------------------------------------------------------------- /src/components/DivChart/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC } from "react"; 2 | import styles from "./DivChart.module.css"; 3 | 4 | const HEIGHTS = new Array(6).fill(0).map(() => 100 * Math.random()); 5 | 6 | const DivChart: FC = () => { 7 | return ( 8 |

9 | {HEIGHTS.map((value) => ( 10 |
17 | ))} 18 |
19 | ); 20 | }; 21 | 22 | export default DivChart; 23 | -------------------------------------------------------------------------------- /src/containers/AppContainer.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { Outlet } from "react-router"; 3 | 4 | import { Navbar } from "../components"; 5 | import { HistoryEntry } from "../interfaces"; 6 | import { HistoryContext } from "../hooks/contexts"; 7 | 8 | const App = () => { 9 | const [history, setHistory] = useState([]); 10 | 11 | return ( 12 | 13 |
14 | 15 | 16 |
17 |
18 | ); 19 | }; 20 | 21 | export default App; 22 | -------------------------------------------------------------------------------- /src/containers/Schools/Schools.module.css: -------------------------------------------------------------------------------- 1 | .schoolsGrid { 2 | display: grid; 3 | grid-gap: 1rem; 4 | grid-template-columns: repeat(4, auto); 5 | margin: 1rem; 6 | } 7 | 8 | @media (max-width: 1200px) { 9 | .schoolsGrid { 10 | grid-template-columns: repeat(3, auto); 11 | } 12 | } 13 | 14 | @media (max-width: 800px) { 15 | .schoolsGrid { 16 | grid-template-columns: repeat(2, auto); 17 | } 18 | } 19 | 20 | @media (max-width: 800px) { 21 | .schoolsGrid { 22 | grid-template-columns: repeat(2, auto); 23 | } 24 | } 25 | 26 | @media (max-width: 500px) { 27 | .schoolsGrid { 28 | grid-gap: 0; 29 | grid-template-columns: repeat(1, auto); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/containers/Courses/Courses.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | margin: 1rem; 3 | } 4 | 5 | .coursesGrid { 6 | display: grid; 7 | grid-gap: 1rem; 8 | grid-template-columns: repeat(4, auto); 9 | } 10 | 11 | @media (max-width: 1200px) { 12 | .coursesGrid { 13 | grid-template-columns: repeat(3, auto); 14 | } 15 | } 16 | 17 | @media (max-width: 800px) { 18 | .coursesGrid { 19 | grid-template-columns: repeat(2, auto); 20 | } 21 | } 22 | 23 | @media (max-width: 800px) { 24 | .coursesGrid { 25 | grid-template-columns: repeat(2, auto); 26 | } 27 | } 28 | 29 | @media (max-width: 500px) { 30 | .coursesGrid { 31 | grid-gap: 0; 32 | grid-template-columns: repeat(1, auto); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/base-styles/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background-color: var(--background-color); 4 | font-family: var(--font-body); 5 | color: var(--text-color); 6 | padding-bottom: 48px; 7 | } 8 | 9 | img { 10 | display: block; 11 | max-width: 100%; 12 | } 13 | 14 | canvas { 15 | width: 100% !important; 16 | height: auto !important; 17 | max-height: 370px; 18 | margin: 20px 0; 19 | } 20 | 21 | a { 22 | color: var(--brand-color); 23 | text-decoration: none; 24 | } 25 | 26 | a:hover { 27 | text-decoration: underline; 28 | } 29 | 30 | h1, 31 | h2, 32 | h3, 33 | h4, 34 | h5, 35 | h6 { 36 | font-family: var(--font-header); 37 | } 38 | 39 | math[display="block"] { 40 | margin: 16px 0; 41 | } 42 | -------------------------------------------------------------------------------- /src/base-styles/colors.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --green: #27ae60; 3 | --green-light: #2ecc71; 4 | --blue: #2470a3; 5 | --blue-light: #2980b9; 6 | --purple: #8e44ad; 7 | --purple-light: #a15fb9; 8 | --yellow: #f39c12; 9 | --yellow-light: #f1c40f; 10 | --orange: #d35400; 11 | --orange-light: #e67e22; 12 | --red: #c0392b; 13 | --red-light: #e74c3c; 14 | --gray: #2c3e50; 15 | --gray-light: #ecf0f1; 16 | --brand-color: var(--blue); 17 | --text-color: var(--gray); 18 | --background-color: var(--gray-light); 19 | } 20 | 21 | @media (prefers-color-scheme: dark) { 22 | :root { 23 | --brand-color: #68afde; 24 | --text-color: var(--gray-light); 25 | --background-color: var(--gray); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/components/Jumbotron/Jumbotron.module.css: -------------------------------------------------------------------------------- 1 | .jumbotron { 2 | padding: 0 60px; 3 | background: none; 4 | margin-bottom: 40px; 5 | } 6 | 7 | .title { 8 | font-family: var(--font-header); 9 | color: var(--brand-color); 10 | font-size: 63px; 11 | font-weight: 500; 12 | letter-spacing: 2px; 13 | } 14 | 15 | .subtitle { 16 | font-size: 24px; 17 | font-weight: 500; 18 | margin-top: 20px; 19 | margin-bottom: 10px; 20 | padding: 0 10px; 21 | } 22 | 23 | @media (max-width: 767px) { 24 | .jumbotron { 25 | padding: 0 20px; 26 | background: none; 27 | margin-bottom: 15px; 28 | } 29 | 30 | .title { 31 | font-size: 36px; 32 | } 33 | 34 | .subtitle { 35 | padding: 0; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /public/_headers: -------------------------------------------------------------------------------- 1 | * 2 | Cache-Control: no-store 3 | Content-Security-Policy: default-src 'none'; connect-src 'self' https://plausible.io; script-src 'self' https://plausible.io; img-src 'self'; style-src 'self'; font-src 'self'; manifest-src 'self'; object-src 'none' 4 | Permissions-Policy: geolocation=(), microphone=() 5 | Referrer-Policy: strict-origin-when-cross-origin 6 | Strict-Transport-Security: max-age=31556926 7 | X-Content-Type-Options: nosniff 8 | X-Frame-Options: SAMEORIGIN 9 | 10 | /assets/* 11 | Cache-Control: immutable 12 | 13 | /data/* 14 | Cache-Control: max-age=604800 15 | 16 | /icons/* 17 | Cache-Control: max-age=604800 18 | 19 | /images/* 20 | Cache-Control: max-age=604800 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true, 22 | "types": ["vite/client"] 23 | }, 24 | "include": ["src"], 25 | "references": [{ "path": "./tsconfig.node.json" }] 26 | } 27 | -------------------------------------------------------------------------------- /public/data/ntnu/tdt4160/Age of Computers: England.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "question": "Hva var Ada Augusta Lovelace kjent for?", 4 | "answers": [3], 5 | "options": [ 6 | "Hun var gift med Charles Babbage.", 7 | "Hun var den første kvinnelige datamaskinkonstruktøren.", 8 | "Hun skrev en artikkel om Pascal sin regnemaskin.", 9 | "Hun var den første programmereren." 10 | ] 11 | }, 12 | { 13 | "question": "Hvem var Charles Babbage?", 14 | "answers": [2], 15 | "options": ["En filosof", "En regnemaskin", "En oppfinner", "En egypter"] 16 | }, 17 | { 18 | "question": "Hva er et hullkort?", 19 | "answers": [2], 20 | "options": ["Et regneverktøy", "En del av prosessoren", "En lagringsenhet"] 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import eslint from "@eslint/js"; 2 | import tseslint from "typescript-eslint"; 3 | import react from "eslint-plugin-react"; 4 | import reactHooks from "eslint-plugin-react-hooks"; 5 | 6 | export default tseslint.config( 7 | eslint.configs.recommended, 8 | tseslint.configs.strictTypeChecked, 9 | { 10 | languageOptions: { 11 | parserOptions: { 12 | projectService: true, 13 | }, 14 | }, 15 | }, 16 | { 17 | ...react.configs.flat.recommended, 18 | settings: { 19 | react: { 20 | version: "detect", 21 | }, 22 | }, 23 | }, 24 | react.configs.flat["jsx-runtime"], 25 | { 26 | plugins: { 27 | "react-hooks": reactHooks, 28 | }, 29 | rules: { ...reactHooks.configs.recommended.rules }, 30 | }, 31 | ); 32 | -------------------------------------------------------------------------------- /src/components/Buttons/Alternative/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC, ReactNode } from "react"; 2 | import { sanitize } from "../../../utils"; 3 | import styles from "./Alternative.module.css"; 4 | 5 | interface Props { 6 | text: string; 7 | type: "alternativeMobile" | "alternative" | "correctAnswer" | "wrongAnswer"; 8 | onClick?: ( 9 | event: 10 | | React.KeyboardEvent 11 | | React.MouseEvent, 12 | ) => void; 13 | children?: ReactNode; 14 | } 15 | 16 | const Alternative: FC = (props) => { 17 | const text = sanitize(props.text); 18 | 19 | return ( 20 |