Simon Bowie 1 ano atrás
pai
commit
e4f4d5932f
20 arquivos alterados com 3096 adições e 632 exclusões
  1. +10
    -37
      web/app/static/js/main.js
  2. +1304
    -0
      web/app/static/package-lock.json
  3. +22
    -0
      web/app/static/package.json
  4. +6
    -0
      web/app/static/postcss.config.js
  5. +149
    -0
      web/app/static/src/main.css
  6. BIN
      web/app/static/styles/ApfelGrotezk-Brukt.woff
  7. BIN
      web/app/static/styles/ApfelGrotezk-Brukt.woff2
  8. BIN
      web/app/static/styles/ApfelGrotezk-Fett.woff
  9. BIN
      web/app/static/styles/ApfelGrotezk-Fett.woff2
  10. BIN
      web/app/static/styles/ApfelGrotezk-Regular.woff
  11. BIN
      web/app/static/styles/ApfelGrotezk-Regular.woff2
  12. +976
    -0
      web/app/static/styles/main.css
  13. +36
    -0
      web/app/static/tailwind.config.js
  14. +3
    -1
      web/app/templates/about.html
  15. +239
    -94
      web/app/templates/base.html
  16. +18
    -61
      web/app/templates/book.html
  17. +25
    -25
      web/app/templates/index.html
  18. +179
    -204
      web/app/templates/resource.html
  19. +127
    -198
      web/app/templates/resources.html
  20. +2
    -12
      web/content/home.md

+ 10
- 37
web/app/static/js/main.js Ver arquivo

@@ -1,38 +1,11 @@
/*
# @name: main.js
# @version: 0.1
# @creation_date: 2022-04-07
# @license: The MIT License <https://opensource.org/licenses/MIT>
# @author: Simon Bowie <ad7588@coventry.ac.uk>
# @purpose: JavaScript functions for various functions
# @acknowledgements:
*/
// document.addEventListener('DOMContentLoaded', e => {
// htmx.logAll();
// let as = document.querySelectorAll('a');
// as.forEach(a => {
// a.addEventListener('click', ee => {
// ee.preventDefault();
// })
// })
// })

// dynamic HTML forms based on dropdown menu
$("#resource_type").change(function() {
var $ = jQuery.noConflict();
var resource_type = $(this).val();
$(".resource_type_input").hide("fast", function() {
$("#resource_type_" + resource_type).show("slow");
});
});

// filtering resources by search
$(document).ready(function(){
$("#searchResources").on("keyup", function() {
var value = $(this).val().toLowerCase();
$("#resource-boxes #resource").filter(function() {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
});
});
});

// testing a couple of ways to expand text
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
})
var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'))
var popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
return new bootstrap.Popover(popoverTriggerEl)
})
// htmx.logAll();

+ 1304
- 0
web/app/static/package-lock.json
Diferenças do arquivo suprimidas por serem muito extensas
Ver arquivo


+ 22
- 0
web/app/static/package.json Ver arquivo

@@ -0,0 +1,22 @@
{
"name": "expub",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"postcss:watch": "postcss ./src/main.css --dir ./styles --watch --verbose"
},
"devDependencies": {
"autoprefixer": "^10.4.2",
"postcss": "^8.4.6",
"postcss-cli": "^9.1.0",
"tailwindcss": "^3.0.18"
},
"author": "",
"license": "ISC",
"dependencies": {

},
"keywords": [],
"description": ""
}

+ 6
- 0
web/app/static/postcss.config.js Ver arquivo

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}

+ 149
- 0
web/app/static/src/main.css Ver arquivo

@@ -0,0 +1,149 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@font-face {
font-family: 'ag';
src: url(ApfelGrotezk-Regular.woff) format("woff");
}

@font-face {
font-family: 'ag-brukt';
src: url(ApfelGrotezk-Brukt.woff) format("woff");
}

@font-face {
font-family: 'ag-fett';
src: url(ApfelGrotezk-Fett.woff) format("woff");
}

body {
font-family: 'ag';
}

strong {
font-family: 'ag-fett';
}

.std-margin {
@apply p-2;
}

.cell-margin {
@apply p-4 pt-4 pb-8 pr-8
}

.block-margin {
@apply mb-8;
}

.std-padding {
@apply p-2;
}

.std-grid {
@apply grid md:grid-cols-2 lg:grid-cols-3;
}

.cell {
@apply cell-margin relative;
/* background: linear-gradient(to right, white 0%, rgb(252, 206, 255) 15px, white 10%, white 100%); */
}

.cell::before {
content: '';
position: absolute;
top: 10px;
right: 0px;
width: 3px;
height: calc(100% - 20px);
background-color: black;
}

.cell::after {
content: '';
position: absolute;
bottom: 0px;
left: 8px;
width: calc(100% - 20px);
height: 3px;
background-color: black;
}

.meta {
transform: rotate(-3.5deg);
}

h2,h3 {
@apply overflow-hidden max-w-full overflow-ellipsis;
}

h2 {
@apply text-4xl;
}

h3 {
font-family: 'ag-fett';
@apply uppercase;
}

.text > h3 {
@apply ml-6 mt-8 ;
}

h2 + *,
h3 + * {
@apply ml-6 mt-1;
}

p {
max-width: 55ch;
}

p + p {
@apply ml-6 mt-[1em];
}

.loading {
opacity: 0;
transition: opacity 200ms ease-in;
}

.htmx-request .loading {
opacity: 1;
display: block;
}


#modal-content main {
opacity: 1;
}
.htmx-request #modal-content main {
/* transition: opacity 0.2s ease; */
opacity: 0;
}

.htmx-request .loading {
opacity: 1;
}

.active {
@apply bg-[#ffff00];
}

.link:hover {
@apply bg-[#ffff00];
}

details[open]::details-content {
display: contents;
}

.text a {
/* font-family: 'ag-fett'; */
text-decoration: underline;
}


BIN
web/app/static/styles/ApfelGrotezk-Brukt.woff Ver arquivo


BIN
web/app/static/styles/ApfelGrotezk-Brukt.woff2 Ver arquivo


BIN
web/app/static/styles/ApfelGrotezk-Fett.woff Ver arquivo


BIN
web/app/static/styles/ApfelGrotezk-Fett.woff2 Ver arquivo


BIN
web/app/static/styles/ApfelGrotezk-Regular.woff Ver arquivo


BIN
web/app/static/styles/ApfelGrotezk-Regular.woff2 Ver arquivo


+ 976
- 0
web/app/static/styles/main.css Ver arquivo

@@ -0,0 +1,976 @@
/*
! tailwindcss v3.2.7 | MIT License | https://tailwindcss.com
*//*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/

*,
::before,
::after {
box-sizing: border-box; /* 1 */
border-width: 0; /* 2 */
border-style: solid; /* 2 */
border-color: #e5e7eb; /* 2 */
}

::before,
::after {
--tw-content: '';
}

/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
5. Use the user's configured `sans` font-feature-settings by default.
*/

html {
line-height: 1.5; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
-moz-tab-size: 4; /* 3 */
-o-tab-size: 4;
tab-size: 4; /* 3 */
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */
font-feature-settings: normal; /* 5 */
}

/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/

body {
margin: 0; /* 1 */
line-height: inherit; /* 2 */
}

/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/

hr {
height: 0; /* 1 */
color: inherit; /* 2 */
border-top-width: 1px; /* 3 */
}

/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/

abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}

/*
Remove the default font size and weight for headings.
*/

h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}

/*
Reset links to optimize for opt-in styling instead of opt-out.
*/

a {
color: inherit;
text-decoration: inherit;
}

/*
Add the correct font weight in Edge and Safari.
*/

b,
strong {
font-weight: bolder;
}

/*
1. Use the user's configured `mono` font family by default.
2. Correct the odd `em` font sizing in all browsers.
*/

code,
kbd,
samp,
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; /* 1 */
font-size: 1em; /* 2 */
}

/*
Add the correct font size in all browsers.
*/

small {
font-size: 80%;
}

/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/

sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}

sub {
bottom: -0.25em;
}

sup {
top: -0.5em;
}

/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/

table {
text-indent: 0; /* 1 */
border-color: inherit; /* 2 */
border-collapse: collapse; /* 3 */
}

/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/

button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
font-weight: inherit; /* 1 */
line-height: inherit; /* 1 */
color: inherit; /* 1 */
margin: 0; /* 2 */
padding: 0; /* 3 */
}

/*
Remove the inheritance of text transform in Edge and Firefox.
*/

button,
select {
text-transform: none;
}

/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/

button,
[type='button'],
[type='reset'],
[type='submit'] {
-webkit-appearance: button; /* 1 */
background-color: transparent; /* 2 */
background-image: none; /* 2 */
}

/*
Use the modern Firefox focus style for all focusable elements.
*/

:-moz-focusring {
outline: auto;
}

/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/

:-moz-ui-invalid {
box-shadow: none;
}

/*
Add the correct vertical alignment in Chrome and Firefox.
*/

progress {
vertical-align: baseline;
}

/*
Correct the cursor style of increment and decrement buttons in Safari.
*/

::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}

/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/

[type='search'] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}

/*
Remove the inner padding in Chrome and Safari on macOS.
*/

::-webkit-search-decoration {
-webkit-appearance: none;
}

/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/

::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}

/*
Add the correct display in Chrome and Safari.
*/

summary {
display: list-item;
}

/*
Removes the default spacing and border for appropriate elements.
*/

blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
margin: 0;
}

fieldset {
margin: 0;
padding: 0;
}

legend {
padding: 0;
}

ol,
ul,
menu {
list-style: none;
margin: 0;
padding: 0;
}

/*
Prevent resizing textareas horizontally by default.
*/

textarea {
resize: vertical;
}

/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
2. Set the default placeholder color to the user's configured gray 400 color.
*/

input::-moz-placeholder, textarea::-moz-placeholder {
opacity: 1; /* 1 */
color: #9ca3af; /* 2 */
}

input::placeholder,
textarea::placeholder {
opacity: 1; /* 1 */
color: #9ca3af; /* 2 */
}

/*
Set the default cursor for buttons.
*/

button,
[role="button"] {
cursor: pointer;
}

/*
Make sure disabled buttons don't get the pointer cursor.
*/
:disabled {
cursor: default;
}

/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
This can trigger a poorly considered lint error in some tools but is included by design.
*/

img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block; /* 1 */
vertical-align: middle; /* 2 */
}

/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/

img,
video {
max-width: 100%;
height: auto;
}

/* Make elements with the HTML hidden attribute stay hidden by default */
[hidden] {
display: none;
}

*, ::before, ::after {
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
}

::backdrop {
--tw-border-spacing-x: 0;
--tw-border-spacing-y: 0;
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
}
.container {
width: 100%;
}
@media (min-width: 640px) {

.container {
max-width: 640px;
}
}
@media (min-width: 768px) {

.container {
max-width: 768px;
}
}
@media (min-width: 1024px) {

.container {
max-width: 1024px;
}
}
@media (min-width: 1280px) {

.container {
max-width: 1280px;
}
}
@media (min-width: 1536px) {

.container {
max-width: 1536px;
}
}
.pointer-events-none {
pointer-events: none;
}
.collapse {
visibility: collapse;
}
.static {
position: static;
}
.fixed {
position: fixed;
}
.absolute {
position: absolute;
}
.relative {
position: relative;
}
.sticky {
position: sticky;
}
.left-0 {
left: 0px;
}
.right-10 {
right: 2.5rem;
}
.top-0 {
top: 0px;
}
.top-10 {
top: 2.5rem;
}
.z-10 {
z-index: 10;
}
.z-20 {
z-index: 20;
}
.z-50 {
z-index: 50;
}
.row-span-2 {
grid-row: span 2 / span 2;
}
.row-span-3 {
grid-row: span 3 / span 3;
}
.row-start-1 {
grid-row-start: 1;
}
.float-right {
float: right;
}
.m-16 {
margin: 4rem;
}
.m-8 {
margin: 2rem;
}
.my-8 {
margin-top: 2rem;
margin-bottom: 2rem;
}
.mx-4 {
margin-left: 1rem;
margin-right: 1rem;
}
.mb-2 {
margin-bottom: 0.5rem;
}
.mb-3 {
margin-bottom: 0.75rem;
}
.mb-4 {
margin-bottom: 1rem;
}
.mb-8 {
margin-bottom: 2rem;
}
.mr-auto {
margin-right: auto;
}
.mt-20 {
margin-top: 5rem;
}
.mt-3 {
margin-top: 0.75rem;
}
.ml-auto {
margin-left: auto;
}
.mb-16 {
margin-bottom: 4rem;
}
.block {
display: block;
}
.flex {
display: flex;
}
.table {
display: table;
}
.grid {
display: grid;
}
.h-10 {
height: 2.5rem;
}
.h-40 {
height: 10rem;
}
.h-full {
height: 100%;
}
.h-screen {
height: 100vh;
}
.w-10 {
width: 2.5rem;
}
.w-40 {
width: 10rem;
}
.w-full {
width: 100%;
}
.w-\[3rem\] {
width: 3rem;
}
.w-\[30rem\] {
width: 30rem;
}
.w-\[20rem\] {
width: 20rem;
}
.w-\[25rem\] {
width: 25rem;
}
.min-w-\[10rem\] {
min-width: 10rem;
}
.max-w-\[30rem\] {
max-width: 30rem;
}
.max-w-\[55ch\] {
max-width: 55ch;
}
.max-w-\[25rem\] {
max-width: 25rem;
}
.shrink-0 {
flex-shrink: 0;
}
.rotate-\[15deg\] {
--tw-rotate: 15deg;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.cursor-pointer {
cursor: pointer;
}
.grid-flow-col {
grid-auto-flow: column;
}
.grid-cols-\[1fr\2c 4fr\] {
grid-template-columns: 1fr 4fr;
}
.items-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.justify-between {
justify-content: space-between;
}
.gap-2 {
gap: 0.5rem;
}
.gap-4 {
gap: 1rem;
}
.gap-8 {
gap: 2rem;
}
.overflow-x-scroll {
overflow-x: scroll;
}
.overflow-y-scroll {
overflow-y: scroll;
}
.overscroll-none {
overscroll-behavior: none;
}
.truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.rounded-full {
border-radius: 9999px;
}
.border-2 {
border-width: 2px;
}
.border-b-\[3px\] {
border-bottom-width: 3px;
}
.border-black {
--tw-border-opacity: 1;
border-color: rgb(0 0 0 / var(--tw-border-opacity));
}
.bg-black {
--tw-bg-opacity: 1;
background-color: rgb(0 0 0 / var(--tw-bg-opacity));
}
.bg-black\/20 {
background-color: rgb(0 0 0 / 0.2);
}
.bg-white {
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.object-contain {
-o-object-fit: contain;
object-fit: contain;
}
.p-2 {
padding: 0.5rem;
}
.p-4 {
padding: 1rem;
}
.p-8 {
padding: 2rem;
}
.p-1 {
padding: 0.25rem;
}
.py-3 {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
}
.pt-4 {
padding-top: 1rem;
}
.text-center {
text-align: center;
}
.align-bottom {
vertical-align: bottom;
}
.text-base {
font-size: 1.08rem;
line-height: 1.35;
}
.text-sm {
font-size: 0.95rem;
line-height: 1.35;
}
.text-xs {
font-size: 0.75rem;
line-height: 1rem;
}
.leading-tight {
line-height: 1.25;
}
.text-red-600 {
--tw-text-opacity: 1;
color: rgb(220 38 38 / var(--tw-text-opacity));
}
.text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.grayscale {
--tw-grayscale: grayscale(100%);
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.filter {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}

@font-face {
font-family: 'ag';
src: url(ApfelGrotezk-Regular.woff) format("woff");
}

@font-face {
font-family: 'ag-brukt';
src: url(ApfelGrotezk-Brukt.woff) format("woff");
}

@font-face {
font-family: 'ag-fett';
src: url(ApfelGrotezk-Fett.woff) format("woff");
}

body {
font-family: 'ag';
}

strong {
font-family: 'ag-fett';
}

.std-margin {
padding: 0.5rem;
}

.cell-margin {
padding: 1rem;
padding-top: 1rem;
padding-bottom: 2rem;
padding-right: 2rem;
}

.block-margin {
margin-bottom: 2rem;
}

.std-padding {
padding: 0.5rem;
}

.std-grid {
display: grid;
}

@media (min-width: 768px) {

.std-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}

@media (min-width: 1024px) {

.std-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}

.cell {
position: relative;
padding: 1rem;
padding-top: 1rem;
padding-bottom: 2rem;
padding-right: 2rem;
/* background: linear-gradient(to right, white 0%, rgb(252, 206, 255) 15px, white 10%, white 100%); */
}

.cell::before {
content: '';
position: absolute;
top: 10px;
right: 0px;
width: 3px;
height: calc(100% - 20px);
background-color: black;
}

.cell::after {
content: '';
position: absolute;
bottom: 0px;
left: 8px;
width: calc(100% - 20px);
height: 3px;
background-color: black;
}

.meta {
transform: rotate(-3.5deg);
}

h2,h3 {
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}

h2 {
font-size: 2.53rem;
line-height: 1;
}

h3 {
font-family: 'ag-fett';
text-transform: uppercase;
}

.text > h3 {
margin-left: 1.5rem;
margin-top: 2rem;
}

h2 + *,
h3 + * {
margin-left: 1.5rem;
margin-top: 0.25rem;
}

p {
max-width: 55ch;
}

p + p {
margin-left: 1.5rem;
margin-top: 1em;
}

.loading {
opacity: 0;
transition: opacity 200ms ease-in;
}

.htmx-request .loading {
opacity: 1;
display: block;
}


#modal-content main {
opacity: 1;
}
.htmx-request #modal-content main {
/* transition: opacity 0.2s ease; */
opacity: 0;
}

.htmx-request .loading {
opacity: 1;
}

.active {
--tw-bg-opacity: 1;
background-color: rgb(255 255 0 / var(--tw-bg-opacity));
}

.link:hover {
--tw-bg-opacity: 1;
background-color: rgb(255 255 0 / var(--tw-bg-opacity));
}

details[open]::details-content {
display: contents;
}

.text a {
/* font-family: 'ag-fett'; */
text-decoration: underline;
}

@media (min-width: 1024px) {

.lg\:flex {
display: flex;
}

.lg\:grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}

.lg\:grid-rows-3 {
grid-template-rows: repeat(3, minmax(0, 1fr));
}
}


+ 36
- 0
web/app/static/tailwind.config.js Ver arquivo

@@ -0,0 +1,36 @@
module.exports = {
mode: 'jit',
content: [
'../templates/*.html'
],
theme: {
extend: {
fontSize: {
// xs: ['0.95rem', { lineHeight: '1.35' }],
sm: ['0.95rem', { lineHeight: '1.35' }],
base: ['1.08rem', { lineHeight: '1.35' }],
// lg: ['1.125rem', { lineHeight: '1.5' }],
// xl: ['1.25rem', { lineHeight: '1.6' }],
// '2xl': ['1.5rem', { lineHeight: '1.88rem' }],
// '3xl': ['1.875rem', { lineHeight: '2.25rem' }],
'4xl': ['2.53rem', { lineHeight: '1' }],
// '5xl': ['3rem', { lineHeight: '1.1' }],
// '6xl': ['3.75rem', { lineHeight: '1.04' }],
// '7xl': ['4.5rem', { lineHeight: '1.1' }],
// '8xl': ['6rem', { lineHeight: '1' }],
// '9xl': ['8rem', { lineHeight: '1' }],
},
colors: {
// 'ggreen': {
// light: '#67e8f9',
// DEFAULT: 'var(--primary-color)',
// dark: '#0e7490',
// },
},
}
},
variants: {
extend: {},
},
plugins: [],
}

+ 3
- 1
web/app/templates/about.html Ver arquivo

@@ -2,6 +2,8 @@

{% block content %}

{{ text|safe }}
<div class="cell-margin text max-w-[55ch]">
{{ text|safe }}
</div>

{% endblock %}

+ 239
- 94
web/app/templates/base.html Ver arquivo

@@ -12,6 +12,108 @@
# Boostrap select: https://stackoverflow.com/questions/67942546/bootstrap-5-select-dropdown-with-the-multiple-attribute-collapsed
-->

{% macro popup_link(title,url) %}
<a href="{{ url }}" class="nav-link">
{{ title }}
</a>
{% endmacro %}

{% macro resource_lead(type, title, leadtext, url, year, thumbnail='', large_title=false) %}
<div class="relative cell h-full">
<a
class="block cursor-pointer"

href="{{ url }}"
hx-target="#modal-content"
hx-select="main"
hx-swap="innerHTML"

@click="openModal()"
>

{% if large_title %}
<h2 class="">{{ title }}</h2>
{% else %}
<h3 class="">{{ title }}</h3>
{% endif %}
{% if year %}
<div class="">{{ year }}</div>
{% endif %}

{% if type == 'book' and thumbnail %}
<img class="w-40 h-40 object-contain float-right m-16 grayscale rotate-[15deg]" src={{ book['thumbnail'] }} alt="cover for {{ title }}">
{% endif %}

<div class="">
{{ leadtext | truncate(100) }}
</div>
</a>
{% if current_user.is_authenticated %}
<div class="">
{% if resource['type'] == 'tool' %}
<a href="{{ url_for('tool.edit_tool', tool_id=resource['id']) }}">
<span class="absolute top-0 left-0 text-xs">Edit</span>
</a>
{% elif resource['type'] == 'practice' %}
<a href="{{ url_for('practice.edit_practice', practice_id=resource['id']) }}">
<span class="absolute top-0 left-0 text-xs">Edit</span>
</a>
{% elif resource['type'] == 'book' %}
<a href="{{ url_for('book.edit_book', book_id=resource['id']) }}">
<span class="absolute top-0 left-0 text-xs">Edit</span>
</a>
{% endif %}
</div>
{% endif %}
</div>

{% endmacro %}

{% macro resource_small(resource) %}
{% if resource['type'] == 'tool' %}
{{
resource_lead(
resource['type'],
resource['name'],
resource['description'],
url_for('tool.show_tool',
tool_id=resource['id']),
null,
'',
true
)
}}
{% elif resource['type'] == 'practice' %}
{{
resource_lead(
resource['type'],
resource['name'],
resource['description'],
url_for('practice.show_practice',
practice_id=resource['id']),
null
)
}}
{% elif resource['type'] == 'book' %}
{{
resource_lead(
resource['type'],
resource['name'],
resource['author'],
url_for('book.show_book',
book_id=resource['id']),
null,
resource['thumbnail'],
true
)
}}
{% endif %}
{% endmacro %}


<!DOCTYPE html>
<html>

@@ -20,111 +122,154 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://unpkg.com/htmx.org@1.8.6"></script>
<script src="//unpkg.com/alpinejs" defer></script>
<title>ExPub Compendium</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link href="{{ url_for('static',filename='styles/custom.css') }}" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.14.0-beta2/css/bootstrap-select.min.css" integrity="sha512-mR/b5Y7FRsKqrYZou7uysnOdCIJib/7r5QeJMFvLNHNhtye3xJp1TdJVPLtetkukFn227nKpXD9OjUc09lx97Q==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link href="{{ url_for('static',filename='styles/main.css') }}" rel="stylesheet">
</head>

<body class="d-flex flex-column min-vh-100">

<header>
<!-- Fixed navbar -->
<nav class="navbar navbar-expand-md navbar-light sticky-top">
<a class="navbar-brand" href="{{ url_for('main.index')}}">ExPub Compendium</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a href="{{ url_for('main.about') }}" class="nav-link">
About
</a>
</li>
<li class="nav-item">
<a href="{{ url_for('tool.get_tools') }}" class="nav-link">
Tools
</a>
</li>
<li class="nav-item">
<a href="{{ url_for('practice.get_practices') }}" class="nav-link">
Practices
</a>
</li>
<li class="nav-item">
<a href="{{ url_for('book.get_books') }}" class="nav-link">
Books
</a>
</li>
{% if current_user.is_authenticated %}
<li class="nav-item">
<a href="{{ url_for('create.create_resource') }}" class="nav-link">
Add resource
</a>
</li>
{% endif %}
{% if current_user.is_authenticated %}
<li class="nav-item">
<a href="{{ url_for('main.profile') }}" class="nav-link">
Profile
</a>
</li>
{% endif %}
{% if not current_user.is_authenticated %}
<li class="nav-item">
<a href="{{ url_for('auth.login') }}" class="nav-link">
Login
</a>
</li>
<li class="nav-item">
<a href="{{ url_for('auth.signup') }}" class="nav-link">
Sign Up
</a>
</li>
{% endif %}
{% if current_user.is_authenticated %}
<li class="nav-item">
<a href="{{ url_for('auth.logout') }}" class="nav-link">
Logout
</a>
</li>
<script>
// htmx.on('htmx:beforeRequest', e=> {
// console.log(e)
// })
// htmx.logAll()
function base() {
return {
menuOpen: false,
modalOpen: false,
showRelated: false,
home: '/',
hideIfBase() {
let str = document.location.toString();
str = str.replace('http://', '');
str = str.replace('https://', '');
let l = str.split('/').length-1;
if(l<2) {
this.modalOpen = false;
}
return l;
},
init() {
this.$watch('document.location', (value, oldValue) => {
console.log('new url', value);
});
window.addEventListener('popstate', e => {
this.hideIfBase();
});
},
hideOverlay() {
this.modalOpen = false;
// window.history.pushState({}, '', this.home);
},
openModal() {
// this.$refs.modal.innerHTML = '';
this.modalOpen = true;
let mc = document.querySelector('#modal-content');
mc.scrollTo(0,0);
}
}
}
</script>
<body
class="text-base overflow-y-scroll"
x-data="base()"
hx-boost="true"
hx-select="#all"
hx-target="#all"
hx-swap="outerHTML"
hx-indicator="body"
>
<div id="loading" class="loading">
<div class="pointer-events-none fixed top-0 left-0 w-full h-screen z-50 flex justify-center items-center p-4">
<div class="rounded-full bg-black text-white p-4 ">
Loading...
</div>
</div>
</div>
<div id="all">
<header class="sticky top-0 z-10 bg-white std-padding border-b-[3px] border-black">
<nav class="">
<div class="lg:flex gap-2 mb-2">
<a class="link leading-tight" href="{{ url_for('main.index') }}">ExPub<br>Compendium</a>
<a href="{{ url_for('main.about') }}" class="{{ 'active' if request.path == url_for('main.about') }} ml-auto link">
About
</a>
{% if current_user.is_authenticated %}
<a href="{{ url_for('create.create_resource') }}" class="link">
Add resource
</a>
{% endif %}
{% if current_user.is_authenticated %}
<a href="{{ url_for('main.profile') }}" class="link">
Profile
</a>
{% endif %}
{% if not current_user.is_authenticated %}
<a href="{{ url_for('auth.login') }}" class="link">
Login
</a>
<a href="{{ url_for('auth.signup') }}" class="link">
Sign Up
</a>
{% endif %}
{% if current_user.is_authenticated %}
<a href="{{ url_for('auth.logout') }}" class="link">
Logout
</a>
{% endif %}
</div>
<h2 class="flex gap-4 ">
<a href="{{ url_for('tool.get_tools') }}" class=" link align-bottom">
Tools
</a>
<a href="{{ url_for('practice.get_practices') }}" class="link">
Practices
</a>
<a href="{{ url_for('book.get_books') }}" class="link">
Books
</a>
<input class="ml-auto text-base border-2 border-black p-1 " type="text" placeholder="Search">
</h2>
</nav>
</header>
<!-- Begin page content -->
<main>
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="alert alert-danger">
{{ messages[0] }}
</div>
{% endif %}
</ul>
</div>
</nav>
</header>

<!-- Begin page content -->
<main class="flex-shrink-0">
<div class="layer-bg w-100">
<img class="img-fluid w-100" src="{{ url_for('static',filename='images/dots-bg.png') }}" alt="bg-shape">
</div>
<div class="container-fluid">
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="alert alert-danger">
{{ messages[0] }}
</div>
{% endif %}
{% endwith %}
{% block content %}
{% endblock %}
</div>
</main>
{% endwith %}
{% block content %}
{% endblock %}
</main>
</div>

<div id="modal" x-show="modalOpen" class="modal h-screen w-full fixed top-0 z-20 p-8 bg-black/20 overscroll-none">
<div class="cross cursor-pointer absolute top-10 right-10 w-10 h-10" @click="hideOverlay()">
<svg width="100%" height="100%" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 2L18 18M18 2L2 18" stroke="black" stroke-width="1"></path>
</svg>
</div>
<div id="modal-content" @click.outside="hideOverlay()" x-ref="modal" class="content w-full overflow-y-scroll h-full bg-white " style="box-shadow:0 0 4rem rgba(0,0,0,0.3)">

</div>
</div>

<!-- Sticky footer-->
<footer class="footer py-3 mt-auto" style="background-color: #dcddde;">
<footer class="std-margin mt-20 text-sm">
<div class="container">
<span class="text-muted">© 2022–{{ moment().format('YYYY') }} <a href="https://copim.ac.uk/">COPIM</a> and licensed under a <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License (CC BY 4.0)</a>.</span>
<span class="">© 2022–{{ moment().format('YYYY') }} <a href="https://copim.ac.uk/">COPIM</a> and licensed under a <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License (CC BY 4.0)</a>.</span>
</div>
</footer>
<!-- JavaScript -->
<!-- jQuery first, then Popper JS, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.14.0-beta2/js/bootstrap-select.min.js" integrity="sha512-FHZVRMUW9FsXobt+ONiix6Z0tIkxvQfxtCSirkKc5Sb4TKHmqq1dZa8DphF0XqKb3ldLu/wgMa8mT6uXiLlRlw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="{{ url_for('static',filename='js/main.js') }}"></script>
</body>


+ 18
- 61
web/app/templates/book.html Ver arquivo

@@ -2,23 +2,20 @@

{% block content %}

{% if book['thumbnail'] %}
<img class="img-fluid mx-auto d-block py-3" src={{ book['thumbnail'] }} alt="cover for {{ book['Title'] }}">
{% else %}
<div class="row">
<div class="col">
<h1 class="text-center">{% block title %} {{ book['Title'] or resource['name'] }} {% endblock %}</h1>
</div>
</div>
{% endif %}
{% if current_user.is_authenticated %}
<div class="row text-center py-3">
<a href="{{ url_for('book.edit_book', book_id=resource['id']) }}">
<span class="badge bg-dark">Edit</span>
</a>
</div>
{% endif %}
<div class="row">
<div class="cell-margin">
{% if book['thumbnail'] %}
<img class="w-40 h-40 object-contain float-right m-16 grayscale rotate-[15deg]" src={{ book['thumbnail'] }} alt="cover for {{ book['Title'] }}">
{% endif %}
<h2 class="max-w-[30rem]">{% block title %} {{ book['Title'] or resource['name'] }} {% endblock %}</h2>
{% if current_user.is_authenticated %}
<div class="row text-center py-3">
<a href="{{ url_for('book.edit_book', book_id=resource['id']) }}">
<span class="badge bg-dark">Edit</span>
</a>
</div>
{% endif %}
</div>
<div class="row block-margin">
<div class="col">
<table class="table table-hover">
<tbody>
@@ -165,50 +162,10 @@
</div>
</div>
{% if relationships %}
<div class="row">
<div class="col">
<h2 class="text-center">Linked resources:</h2>
</div>
</div>
<div class="row">
{% for relationship in relationships %}
<div class="col-md-4 col-sm-6 py-3">
{% if relationship['type'] == 'tool' %}
<div class="card text-dark bg-tool mb-3">
<div class="card-body">
<a href="{{ url_for('tool.show_tool', tool_id=relationship['id']) }}">
<h3 class="card-title text-center text-dark">{{ relationship['name'] }}</h3>
</a>
<p class="card-text">
{{ relationship['description']|truncate(100) }}
</p>
</div>
</div>
{% elif relationship['type'] == 'practice' %}
<div class="card text-dark bg-practice mb-3">
<div class="card-body">
<a href="{{ url_for('practice.show_practice', practice_id=relationship['id']) }}">
<h3 class="card-title text-center text-dark">{{ relationship['name'] }}</h3>
</a>
<p class="card-text">
{{ relationship['description']|truncate(100) }}
</p>
</div>
</div>
{% elif relationship['type'] == 'book' %}
<div class="card text-dark bg-book mb-3">
<div class="card-body">
<a href="{{ url_for('book.show_book', book_id=relationship['id']) }}">
<h3 class="card-title text-center text-dark">{{ relationship['name'] }}</h3>
</a>
<p class="card-text">
{{ relationship['description']|truncate(100) }}
</p>
</div>
</div>
{% endif %}
</div>
{% endfor %}
<div class="grid lg:grid-cols-3">
{% for relationship in relationships %}
{{ resource_small(relationship)}}
{% endfor %}
</div>
{% endif %}
{% endblock %}

+ 25
- 25
web/app/templates/index.html Ver arquivo

@@ -1,33 +1,33 @@
{% extends "base.html" %}

{% block content %}
<div class="std-grid">

{{ text|safe }}

<hr>
<p>
Browse from this selection of random tools, search or explore tools, practices, and experimental books.
</p>

<div class="row">
{% for tool in tools %}
<div class="col-md-4 col-sm-6 py-3">
<div class="card text-dark bg-info mb-3">
<div class="card-body">
<a href="{{ url_for('tool.show_tool', tool_id=tool['id']) }}">
<h3 class="card-title text-center text-dark">{{ tool['name'] }}</h3>
</a>
<p class="card-text">
{{ tool['description']|truncate(100) }}
</p>
{% if current_user.is_authenticated %}
<a href="{{ url_for('tool.edit_tool', tool_id=tool['id']) }}">
<span class="badge bg-dark">Edit</span>
</a>
{% endif %}
</div>
<div class="std-margin text row-span-2 cell meta">
{{ text|safe }}
</div>
{% for tool in tools %}

{{ resource_small(tool) }}

{% endfor %}

<div class="cell text-red-600">
MISSING :<br>

Clusters of things (book + tool). SHow books and what tools they're made with, and "tagged" with practice and typology
</div>
{% endfor %}
<div class="cell text-red-600">
MISSING :<br>

Lead into Typology with some examples and lead text
</div>
<div class="cell text-red-600">
MISSING :<br>

Lead into Practices with some examples and lead text
</div>

</div>
{% endblock %}

+ 179
- 204
web/app/templates/resource.html Ver arquivo

@@ -1,213 +1,188 @@
{% extends 'base.html' %}

{% block content %}
<div class="cell-margin">
<div class="cell-margin">
<h2 class="block-margin">
{% block title %}
{% autoescape false %}
{{ resource['name'] | replace(" ","<br>") }}
{% endautoescape %}
{% endblock %}
</h2>
{% if current_user.is_authenticated %}
{% if resource['type'] == 'tool' %}
<div class="row text-center py-3">
<a href="{{ url_for('tool.edit_tool', tool_id=resource['id']) }}">
<span class="">Edit</span>
</a>
</div>
{% elif resource['type'] == 'practice' %}
<div class="row text-center py-3">
<a href="{{ url_for('practice.edit_practice', practice_id=resource['id']) }}">
<span class="">Edit</span>
</a>
</div>
{% endif %}
{% endif %}
<table class="table table-hover">
<tbody>
<tr>
<th>
Created:
</th>
<td>
{{ resource['created'].strftime("%Y-%m-%d %H:%M") }} UTC
</td>
</tr>
{% if resource['description'] %}
<tr>
<th>
Description:
</th>
<td>
{{ resource['description'] }}
</td>
</tr>
{% endif %}
<!-- fields for tools -->
{% if resource['developer'] %}
<tr>
<th>
Developer
</th>
<td>
{% if resource['developerUrl'] %}
<a href="{{ resource['developerUrl'] }}">{{ resource['developer'] }}</a>
{% else %}
{{ resource['developer'] }}
{% endif %}
</td>
</tr>
{% endif %}
{% if resource['license'] %}
<tr>
<th>
Software license:
</th>
<td>
{{ resource['license'] }}
</td>
</tr>
{% endif %}
{% if resource['scriptingLanguage'] %}
<tr>
<th>
Software language(s):
</th>
<td>
{{ resource['scriptingLanguage'] }}
</td>
</tr>
{% endif %}
{% if resource['projectUrl'] %}
<tr>
<th>
Project page:
</th>
<td>
<a href="{{ resource['projectUrl'] }}">{{ resource['projectUrl'] }}</a>
</td>
</tr>
{% endif %}
{% if resource['repositoryUrl'] %}
<tr>
<th>
Code repository:
</th>
<td>
<a href="{{ resource['repositoryUrl'] }}">{{ resource['repositoryUrl'] }}</a>
</td>
</tr>
{% endif %}
{% if resource['ingestFormats'] %}
<tr>
<th>
Import / ingest formats:
</th>
<td>
{{ resource['ingestFormats'] }}
</td>
</tr>
{% endif %}
{% if resource['outputFormats'] %}
<tr>
<th>
Output formats:
</th>
<td>
{{ resource['outputFormats'] }}
</td>
</tr>
{% endif %}
{% if resource['status'] %}
<tr>
<th>
Platform status:
</th>
<td>
{{ resource['status'] }}
</td>
</tr>
{% endif %}
<!-- fields for practices -->
{% if resource['longDescription'] %}
<tr>
<th>
Full description
</th>
<td>
{{ resource['longDescription']|safe }}
</td>
</tr>
{% endif %}
{% if resource['experimental'] %}
<tr>
<th>
Experimental uses
</th>
<td>
{{ resource['experimental']|safe }}
</td>
</tr>
{% endif %}
{% if resource['considerations'] %}
<tr>
<th>
Considerations
</th>
<td>
<p style="white-space: pre-line">{{ resource['considerations']|safe }}</p>
</td>
</tr>
{% endif %}
{% if resource['references'] %}
<tr>
<th>
References:
</th>
<td>
<p style="white-space: pre-line">{{ resource['references']|safe }}</p>
</td>
</tr>
{% endif %}
</tbody>
</table>

<div class="row">
<div class="col">
<h1 class="text-center">{% block title %} {{ resource['name'] }} {% endblock %}</h1>
</div>
</div>
{% if current_user.is_authenticated %}
{% if resource['type'] == 'tool' %}
<div class="row text-center py-3">
<a href="{{ url_for('tool.edit_tool', tool_id=resource['id']) }}">
<span class="badge bg-dark">Edit</span>
</a>
</div>
{% elif resource['type'] == 'practice' %}
<div class="row text-center py-3">
<a href="{{ url_for('practice.edit_practice', practice_id=resource['id']) }}">
<span class="badge bg-dark">Edit</span>
</a>
</div>
{% endif %}
{% endif %}
<div class="row">
<div class="col">
<table class="table table-hover">
<tbody>
<tr>
<th>
Created:
</th>
<td>
{{ resource['created'].strftime("%Y-%m-%d %H:%M") }} UTC
</td>
</tr>
{% if resource['description'] %}
<tr>
<th>
Description:
</th>
<td>
{{ resource['description'] }}
</td>
</tr>
{% endif %}
<!-- fields for tools -->
{% if resource['developer'] %}
<tr>
<th>
Developer
</th>
<td>
{% if resource['developerUrl'] %}
<a href="{{ resource['developerUrl'] }}">{{ resource['developer'] }}</a>
{% else %}
{{ resource['developer'] }}
{% endif %}
</td>
</tr>
{% endif %}
{% if resource['license'] %}
<tr>
<th>
Software license:
</th>
<td>
{{ resource['license'] }}
</td>
</tr>
{% endif %}
{% if resource['scriptingLanguage'] %}
<tr>
<th>
Software language(s):
</th>
<td>
{{ resource['scriptingLanguage'] }}
</td>
</tr>
{% endif %}
{% if resource['projectUrl'] %}
<tr>
<th>
Project page:
</th>
<td>
<a href="{{ resource['projectUrl'] }}">{{ resource['projectUrl'] }}</a>
</td>
</tr>
{% endif %}
{% if resource['repositoryUrl'] %}
<tr>
<th>
Code repository:
</th>
<td>
<a href="{{ resource['repositoryUrl'] }}">{{ resource['repositoryUrl'] }}</a>
</td>
</tr>
{% endif %}
{% if resource['ingestFormats'] %}
<tr>
<th>
Import / ingest formats:
</th>
<td>
{{ resource['ingestFormats'] }}
</td>
</tr>
{% endif %}
{% if resource['outputFormats'] %}
<tr>
<th>
Output formats:
</th>
<td>
{{ resource['outputFormats'] }}
</td>
</tr>
{% endif %}
{% if resource['status'] %}
<tr>
<th>
Platform status:
</th>
<td>
{{ resource['status'] }}
</td>
</tr>
{% endif %}
<!-- fields for practices -->
{% if resource['longDescription'] %}
<tr>
<th>
Full description
</th>
<td>
{{ resource['longDescription']|safe }}
</td>
</tr>
{% endif %}
{% if resource['experimental'] %}
<tr>
<th>
Experimental uses
</th>
<td>
{{ resource['experimental']|safe }}
</td>
</tr>
{% endif %}
{% if resource['considerations'] %}
<tr>
<th>
Considerations
</th>
<td>
<p style="white-space: pre-line">{{ resource['considerations']|safe }}</p>
</td>
</tr>
{% endif %}
{% if resource['references'] %}
<tr>
<th>
References:
</th>
<td>
<p style="white-space: pre-line">{{ resource['references']|safe }}</p>
</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</div>
</div>
{% if relationships %}
<div class="row">
<div class="col">
<h2 class="text-center">Linked resources:</h2>
</div>
</div>
<div class="row">
{% for relationship in relationships %}
<div class="col-md-4 col-sm-6 py-3">
{% if relationship['type'] == 'tool' %}
<div class="card text-dark bg-tool mb-3">
<div class="card-body">
<a href="{{ url_for('tool.show_tool', tool_id=relationship['id']) }}">
<h3 class="card-title text-center text-dark">{{ relationship['name'] }}</h3>
</a>
<p class="card-text">
{{ relationship['description']|truncate(100) }}
</p>
</div>
</div>
{% elif relationship['type'] == 'practice' %}
<div class="card text-dark bg-practice mb-3">
<div class="card-body">
<a href="{{ url_for('practice.show_practice', practice_id=relationship['id']) }}">
<h3 class="card-title text-center text-dark">{{ relationship['name'] }}</h3>
</a>
<p class="card-text">
{{ relationship['description']|truncate(100) }}
</p>
</div>
</div>
{% endif %}
</div>
{% endfor %}
<div class="grid lg:grid-cols-3">
{% for relationship in relationships %}
{{ resource_small(relationship) }}
{% endfor %}
</div>
{% endif %}
{% endblock %}

+ 127
- 198
web/app/templates/resources.html Ver arquivo

@@ -2,209 +2,138 @@

{% block content %}

<div class="row">
<div class="col-12 text-center">
<h1>{% block title %}
{{ type|capitalize + 's' }}
{% endblock %}
</h1>
</div>
</div>
<div class="row">
<div class="col-12 text-center">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget viverra magna. Nam in ante ultricies purus feugiat vestibulum et ac erat. Donec in sagittis ante. Maecenas non mauris et eros commodo fringilla. Integer accumsan ullamcorper diam, non rhoncus tellus molestie ut. Maecenas finibus pretium dolor ac sagittis.
</p>
</div>
</div>
<div class="row">
<div class="col-md-4 col-lg-3 py-3">
<div class="search-filter-sidebar">
<input class="form-control" id="searchResources" type="text" placeholder="filter by search...">
<div class="row">
{% if practices_filter %}
<div class="col-sm-6 d-md-block d-sm-none d-none">
<div class="filter-title">Practices</div>
<ul class="filter-items">
{% for practice in practices_filter %}
<li {% if request.args.get('practice') == practice[0]|string %} class="fw-bold"{% endif %}>
<a href="/{{type + 's'}}?practice={{practice[0]}}">{{ practice[1] }}</a>
</li>
{% endfor %}
</ul>
</div>
<div class="d-md-none accordion">
<div class="accordion-item">
<div class="filter-title accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#filter-practice">Practices</div>
<div class="accordion-body">
<ul id="filter-practice" class="collapse filter-items">
{% for practice in practices_filter %}
<li {% if request.args.get('practice') == practice[0]|string %} class="fw-bold"{% endif %}>
<a href="/{{type + 's'}}?practice={{practice[0]}}">{{ practice[1] }}</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endif %}
{% if year_filter %}
<div class="col-sm-6 d-md-block d-sm-none d-none">
<div class="filter-title">Year</div>
<ul class="filter-items">
{% for year in year_filter %}
<li {% if request.args.get('year') == year %} class="fw-bold"{% endif %}>
<a href="/books?year={{year}}">{{ year }}</a>
</li>
{% endfor %}
</ul>
</div>
<div class="d-md-none accordion">
<div class="accordion-item">
<div class="filter-title accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#filter-year">Year</div>
<div class="accordion-body">
<ul id="filter-year" class="collapse filter-items">
{% for year in year_filter %}
<li {% if request.args.get('year') == year %} class="fw-bold"{% endif %}>
<a href="/books?year={{year}}">{{ year }}</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endif %}
</div>
<div class="row">
{% if typology_filter %}
<div class="col-sm-6 d-md-block d-sm-none d-none">
<div class="filter-title">Typology category</div>
<ul class="filter-items">
{% for typology in typology_filter %}
<li {% if request.args.get('typology') == typology %} class="fw-bold"{% endif %}>
<a href="/books?typology={{typology}}">{{ typology }}</a>
</li>
{% endfor %}
</ul>
</div>
<div class="d-md-none accordion">
<div class="accordion-item">
<div class="filter-title accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#filter-typology">Typology category</div>
<div class="accordion-body">
<ul id="filter-typology" class="collapse filter-items">
{% for typology in typology_filter %}
<li {% if request.args.get('typology') == typology %} class="fw-bold"{% endif %}>
<a href="/books?typology={{typology}}">{{ typology }}</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endif %}
{% if languages_filter %}
<div class="col-sm-6 d-md-block d-sm-none d-none">
<div class="filter-title">Scripting languages</div>
<ul class="filter-items">
{% for language in languages_filter %}
<li {% if request.args.get('scriptingLanguage') == language %} class="fw-bold"{% endif %}>
<a href="/tools?scriptingLanguage={{language}}">{{ language }}</a>
</li>
{% endfor %}
</ul>
</div>
<div class="d-md-none accordion">
<div class="accordion-item">
<div class="filter-title accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#filter-language">Scripting language</div>
<div class="accordion-body">
<ul id="filter-language" class="collapse filter-items">
{% for language in languages_filter %}
<li {% if request.args.get('scriptingLanguage') == language %} class="fw-bold"{% endif %}>
<a href="/tools?scriptingLanguage={{language}}">{{ language }}</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endif %}
{% if licenses_filter %}
<div class="col-sm-6 d-md-block d-sm-none d-none">
<div class="filter-title">License</div>
<ul class="filter-items">
{% for license in licenses_filter %}
<li {% if request.args.get('license') == license %} class="fw-bold"{% endif %}>
<a href="/tools?license={{license}}">{{ license }}</a>
</li>
{% endfor %}
</ul>
</div>
<div class="d-md-none accordion">
<div class="accordion-item">
<div class="filter-title accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#filter-license">License</div>
<div class="accordion-body">
<ul id="filter-license" class="collapse filter-items">
{% for license in licenses_filter %}
<li {% if request.args.get('license') == license %} class="fw-bold"{% endif %}>
<a href="/tools?license={{license}}">{{ license }}</a>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endif %}
</div>
<!-- <div class="cell-margin">
<div class="mb-8">
<h2>
{% block title %}
{% autoescape false %}
{{ type + 's' | replace(" ","<br>") }}
{% endautoescape %}
{% endblock %}
</h2>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque eget viverra magna. Nam in ante ultricies
purus feugiat vestibulum et ac erat. Donec in sagittis ante. Maecenas non mauris et eros commodo fringilla.
Integer accumsan ullamcorper diam, non rhoncus tellus molestie ut. Maecenas finibus pretium dolor ac sagittis.
</p>
</div>
</div> -->
<script>
function filter() {
return {
filterOpen: false,
init() {
// console.log(this.showRelated)
}
}
}
</script>
<div class="" x-data="filter()">
<div
class="search fixed z-20 top-0 left-0 w-[20rem] h-screen bg-white cell-padding "
x-show="filterOpen"
style="box-shadow:0 0 2rem rgba(0,0,0,0.3)"
@click.outside = "filterOpen = false"
>
<div class=" p-2 pt-4 gap-8 bg-white ">
{% if practices_filter %}
<details class="" open>
<summary>Practices</summary>
<div class="">
{% for practice in practices_filter %}
<div {% if request.args.get('practice')==practice[0]|string %} class="active" {% endif %}>
<a href="/{{type + 's'}}?practice={{practice[0]}}">{{ practice[1] }}</a>
</div>
{% endfor %}
</div>
</details>
{% endif %}
{% if year_filter %}
<details class="">
<summary>Year</summary>
<div id="filter-year" class="collapse filter-items">
{% for year in year_filter %}
<li {% if request.args.get('year')==year %} class="active" {% endif %}>
<a href="/books?year={{year}}">{{ year }}</a>
</li>
{% endfor %}
</div>
<div class="col-md-8 col-lg-9">
<div id="resource-boxes" class="row">
{% for resource in resources %}
<div id="resource" class="col-md-4 col-sm-6 py-3">
<div class="card text-dark bg-{{type}} mb-3">
<div class="card-body">
{% if resource['type'] == 'tool' %}
<a href="{{ url_for('tool.show_tool', tool_id=resource['id']) }}">
<h3 class="card-title text-center text-dark">{{ resource['name'] }}</h3>
</a>
<p class="card-text">
{{ resource['description']|truncate(100) }}
</p>
{% elif resource['type'] == 'practice' %}
<a href="{{ url_for('practice.show_practice', practice_id=resource['id']) }}">
<h3 class="card-title text-center text-dark">{{ resource['name'] }}</h3>
</a>
<p class="card-text">
{{ resource['description']|truncate(100) }}
</p>
{% elif resource['type'] == 'book' %}
<a href="{{ url_for('book.show_book', book_id=resource['id']) }}">
<h3 class="card-title text-center text-dark">{{ resource['name'] }}</h3>
</a>
<p class="card-text text-center">
{{ resource['author']|truncate(100) }}
</p>
{% endif %}
{% if current_user.is_authenticated %}
{% if resource['type'] == 'tool' %}
<a href="{{ url_for('tool.edit_tool', tool_id=resource['id']) }}">
<span class="badge bg-dark">Edit</span>
</a>
{% elif resource['type'] == 'practice' %}
<a href="{{ url_for('practice.edit_practice', practice_id=resource['id']) }}">
<span class="badge bg-dark">Edit</span>
</a>
{% elif resource['type'] == 'book' %}
<a href="{{ url_for('book.edit_book', book_id=resource['id']) }}">
<span class="badge bg-dark">Edit</span>
</a>
{% endif %}
{% endif %}
</div>
</details>
{% endif %}
{% if typology_filter %}
<details class="">
<summary class="">Typology category</summary>
<div class="">
{% for typology in typology_filter %}
<div {% if request.args.get('typology')==typology %} class="active" {% endif %}>
<a href="/books?typology={{typology}}">{{ typology }}</a>
</div>
{% endfor %}
</div>
</details>
{% endif %}
{% if languages_filter %}
<details class="">
<summary>Scripting languages</summary>
<div class="">
{% for language in languages_filter %}
<div {% if request.args.get('scriptingLanguage')==language %} class="active" {% endif %}>
<a href="/tools?scriptingLanguage={{language}}">{{ language }}</a>
</div>
{% endfor %}
</div>
</details>
{% endif %}
{% if licenses_filter %}
<details class="min-w-[10rem]">
<summary>License</summary>
<div class="">
{% for license in licenses_filter %}
<div {% if request.args.get('license')==license %} class="active" {% endif %}>
<a href="/tools?license={{license}}">{{ license }}</a>
</div>
{% endfor %}
</div>
</details>
{% endif %}
</div>
</div>
<div class="flex justify-between mx-4 my-8">
<div class="cursor-pointer" @click="filterOpen = true">← Show filters</div>
<div class="">
<input type="checkbox" name="filter-open" x-model="showRelated" id=""> Also show everything related
</div>
{% endblock %}
</div>
<div class="grid lg:grid-cols-3" x-show="!showRelated">
{% for resource in resources %}
{{ resource_small(resource) }}
{% endfor %}
</div>
<div x-show="showRelated">
{% for resource in resources %}
<div class="w-full overflow-x-scroll">
<div class="grid lg:grid-rows-3 grid-flow-col mb-16">
<div class="w-[25rem] shrink-0 row-span-3 h-full">
{{ resource_small(resource) }}
</div>
<div class="w-[25rem] cell row-start-1">
Something Related
</div>
<div class="w-[25rem] cell shrink-0 row-start-1">
Something Related
</div>
<div class="w-[25rem] cell shrink-0 row-start-1">
Something Related
</div>
<div class="w-[25rem] cell shrink-0 row-start-1">
Something Related
</div>
</div>
</div>
{% endfor %}
</div>
</div>

{% endblock %}

+ 2
- 12
web/content/home.md Ver arquivo

@@ -1,15 +1,5 @@
# ExPub Compendium
## ExPub <br>Compendium

The Experimental Publishing Compendium is for authors, designers, publishers, institutions and technologist who challenge, push and redefine the shape, form and rationale of scholarly works. The compendium offers a catalogues of tools, practices, and books to inspire experimental scholarly works.

## How to use the compendium

The compendium catalogues potential ingredients for the making of experimental publications.

- Under [Tools](/tools) you’ll find mostly software that supports experimental publication from collective writing to the annotation and remix of published texts.
- [Practices](/practices) provide inspiration for experimental book making.
- [Books](/books) provides examples of experimental books and those who publish them.

Each item is cross linked so that a practice will take you to relevant tools or examples and vice versa.

The selection is tentative, reflecting the knowledge and biases of the contributors of current and previous versions. If you want to submit or edit anything in the catalogue please do so by doing XXthisXXX.
[About ExPub](/about)

Carregando…
Cancelar
Salvar