51 Commits

Author SHA1 Message Date
3fff2db563 fix: link
Some checks failed
continuous-integration/drone/pr Build is failing
2025-01-20 10:50:44 +01:00
3wc
cc696ee0c8 Switch to self-hosted docker image
All checks were successful
continuous-integration/drone/push Build is passing
2024-12-05 07:49:28 -05:00
bbf8b3baa5 Merge pull request 'Update node Docker tag to v21 (main)' (#35) from renovate/main-node-21.x into main
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
Reviewed-on: coop-cloud/recipes.coopcloud.tech#35
2024-04-06 18:11:27 +00:00
3wc
a5230dfde3 And switch to correct server & secret..
All checks were successful
continuous-integration/drone/push Build is passing
2024-04-01 20:12:43 -03:00
3wc
9ab689f69e Switch to selfhosted stack-ssh-deploy
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-01 20:10:42 -03:00
3wc
e566a6eef4 Add help link for status score
Some checks failed
continuous-integration/drone/push Build is failing
2024-04-01 20:08:46 -03:00
209cdc2770 Update dependency elm to v0.19.1-6
Some checks failed
renovate/artifacts Artifact file update failure
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is failing
2023-11-02 08:02:07 +00:00
2482caf2e0 Update node Docker tag to v21
Some checks failed
continuous-integration/drone/pr Build is failing
2023-10-20 07:02:07 +00:00
d15df0f9e4 Merge pull request 'Update node Docker tag to v20 (main)' (#34) from renovate/main-node-20.x into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: coop-cloud/recipes.coopcloud.tech#34
2023-04-24 08:14:37 +00:00
91f8340ac8 Update node Docker tag to v20
Some checks failed
continuous-integration/drone/pr Build is failing
2023-04-21 07:05:02 +00:00
3wc
6851d2fe1f Add indicator to show active category filter
All checks were successful
continuous-integration/drone/push Build is passing
Closes #33
2023-03-28 23:08:16 -04:00
3wc
e2f9cdd7e2 Tweak text
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-28 21:11:53 -04:00
3wc
6ed6cbb33e Further filtering tweaks
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-28 19:35:57 -04:00
41ccf212a9 Merge pull request 'Homepage re-jig' (#32) from filter-rejig into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: coop-cloud/recipes.coopcloud.tech#32
2023-03-28 17:42:59 +00:00
3wc
382d36d001 Tweak score names, add intro, stylin'
Some checks reported errors
continuous-integration/drone/pr Build was killed
2023-03-28 11:27:12 -04:00
3wc
2dec76fbfd elm-format
Some checks reported errors
continuous-integration/drone/pr Build was killed
2023-03-28 11:25:53 -04:00
3wc
377c8a7d04 Tweak text 'n style 2023-03-28 11:25:53 -04:00
3wc
f7ffc49b76 Some preliminary rejiggin' 2023-03-28 11:25:53 -04:00
3wc
338da444d8 Merge branch 'recipe-versions'
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
2023-03-28 11:22:35 -04:00
3wc
57b4db9bb2 Add preliminary list of recipe versions
Some checks failed
continuous-integration/drone/pr Build is failing
2023-03-28 11:22:10 -04:00
3wc
70307aad9e Attempt at parsing "version" from JSON 2023-03-28 11:22:10 -04:00
af5565dcc5 Merge pull request 'Reinstate score badges, fix sorting' (#29) from recipe-scores into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: coop-cloud/recipes.coopcloud.tech#29
2023-03-28 15:20:22 +00:00
3wc
4a375f3d5f Make logos bigger on recipe detail page
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-28 01:07:06 -04:00
3wc
d8b2192240 Reinstate score badges, fix sorting
Some checks failed
continuous-integration/drone/pr Build is failing
2023-03-26 18:47:47 -04:00
3wc
65ef1d2772 Switch back to Nginx, fix direct URLs
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-23 13:43:43 -04:00
c50635319b Small CSS change to make recipe logo smaller on homepage
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-23 17:20:04 +00:00
3wc
32366b7bf7 Whoops, wrong path
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-25 10:36:14 -08:00
3wc
dbb701a2a4 Fix image (again)
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-25 10:30:53 -08:00
3wc
b761f39247 Fix embarrassing deployment snafus
All checks were successful
continuous-integration/drone/push Build is passing
2023-01-24 09:04:19 -08:00
3wc
a7435c3d37 Switch to static deployment
Some checks reported errors
continuous-integration/drone/push Build was killed
Closes #9

Generates static HTML + JS version of the Elm app, and serves it using
thhtpd, for bonus permacomputing joy.
2023-01-22 20:41:30 -08:00
3wc
429cb371a8 Add AUTHORS 2023-01-22 20:28:35 -08:00
3wc
774c59bfa8 Update package-lock.json 2023-01-22 20:28:14 -08:00
3wc
39c3122230 Merge remote-tracking branches 'origin/renovate/main-chokidar-cli-3.x' and 'origin/renovate/main-elm-0.x' 2023-01-22 20:26:27 -08:00
3wc
a7ea4207ce Update attribution 2023-01-22 20:25:11 -08:00
6769455c27 Update dependency chokidar-cli to v3
Some checks failed
renovate/artifacts Artifact file update failure
continuous-integration/drone/pr Build is failing
2023-01-20 08:15:30 +00:00
984c205299 Update dependency elm to v0.19.1-5
Some checks failed
renovate/artifacts Artifact file update failure
continuous-integration/drone/pr Build is failing
2023-01-20 08:14:25 +00:00
5b28441102 Merge pull request 'Configure Renovate' (#19) from renovate/configure into main
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: coop-cloud/recipes.coopcloud.tech#19
2023-01-19 10:55:02 +00:00
d278ec2ad4 Add renovate.json
Some checks failed
continuous-integration/drone/pr Build is failing
2023-01-19 08:11:18 +00:00
3wc
3f10abe1c5 Fix Drone badge links
[ci skip]
2023-01-08 19:06:45 -08:00
3wc
1a7ade0f76 Drop CORS proxy
All checks were successful
continuous-integration/drone/push Build is passing
RE: #18
2023-01-08 19:04:39 -08:00
3wc
0777f7c008 Old URL work pls
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
2022-05-08 17:43:36 +01:00
3wc
69a7fbc036 More URL fixin'
All checks were successful
continuous-integration/drone/push Build is passing
2022-05-04 10:30:54 +01:00
3wc
4c5e151615 Rename stack for manual deploy
All checks were successful
continuous-integration/drone/push Build is passing
2022-05-04 10:25:46 +01:00
3wc
9548d0715e Fix deployment
All checks were successful
continuous-integration/drone/push Build is passing
2022-05-04 10:25:32 +01:00
3wc
68669b7445 Add manual deploy instructions
Some checks reported errors
continuous-integration/drone/push Build was killed
2022-05-04 10:25:18 +01:00
1c306e8607 disable for now
Some checks reported errors
continuous-integration/drone/push Build was killed
2022-05-04 11:20:19 +02:00
375cafb946 more naming fixups
Some checks reported errors
continuous-integration/drone/push Build was killed
2022-05-04 11:19:28 +02:00
910d0bf2ae fixup that title
All checks were successful
continuous-integration/drone/push Build is passing
2022-05-04 11:16:14 +02:00
3wc
31f8a0be69 Add missing arguments to Http.expect 🤔🤔🤔
All checks were successful
continuous-integration/drone/push Build is passing
2022-05-04 09:58:33 +01:00
3wc
9c4522dceb Switch URL, upd8 README
Some checks failed
continuous-integration/drone/push Build is failing
2022-05-03 18:57:37 +01:00
83f0919cd8 Merge pull request 'Change dev.site to recipes.site' (#16) from em_change-site into main
Some checks reported errors
continuous-integration/drone/push Build was killed
Reviewed-on: coop-cloud/recipes.coopcloud.tech#16
2022-05-03 16:06:46 +00:00
17 changed files with 651 additions and 435 deletions

View File

@ -1,24 +1,25 @@
---
kind: pipeline
name: deploy to dev.apps.coopcloud.tech
name: deploy to recipes.coopcloud.tech
steps:
- name: build image
image: plugins/docker
settings:
username:
from_secret: docker_reg_username_3wc
username: 3wordchant
password:
from_secret: docker_reg_passwd_3wc
repo: 3wordchant/abra-apps
from_secret: git_coopcloud_tech_token_3wc
repo: git.coopcloud.tech/coop-cloud/recipes.coopcloud.tech
tags: latest
registry: git.coopcloud.tech
- name: deployment
image: decentral1se/stack-ssh-deploy:latest
image: git.coopcloud.tech/coop-cloud/stack-ssh-deploy:latest
settings:
stack: dev_apps_coopcloud_tech
stack: recipes_coopcloud_tech
host: swarm-0.coopcloud.tech
deploy_key:
from_secret: drone_ssh_swarm-demo.autonomic.zone
host: swarm-demo.autonomic.zone
from_secret: drone_ssh_swarm-0_coopcloud_tech
trigger:
branch:
- main

8
AUTHORS.md Normal file
View File

@ -0,0 +1,8 @@
# authors
> If you're looking at this and you hack on `abra` and you're not listed here,
> please do add yourself! This is a community project, let's show some :heart:
- 3wordchant
- eejum
- hazelnot

View File

@ -1,4 +1,4 @@
FROM node:12-alpine
FROM node:21-alpine AS build
RUN mkdir /code
WORKDIR /code
@ -11,5 +11,10 @@ ENV PATH=$PATH:/code/node_modules/elm-linter/bin:/code/node_modules/elm-format/b
# Add remainder of files
COPY . .
ENTRYPOINT ["/usr/local/bin/npm"]
CMD ["run", "prod"]
RUN ["npm", "run", "build"]
FROM nginx
COPY --from=build /code/public/ /usr/share/nginx/html/
COPY ./nginx.conf /etc/nginx/conf.d/default.conf

View File

@ -1,8 +1,8 @@
# recipes.coopcloud.tech
> WIP! https://dev.apps.coopcloud.tech is the current live site
> https://recipes.coopcloud.tech is the current live site
[![Build Status](https://drone.autonomic.zone/api/badges/coop-cloud/recipes.coopcloud.tech/status.svg?ref=refs/heads/main)](https://drone.autonomic.zone/coop-cloud/recipes.coopcloud.tech)
[![Build Status](https://build.coopcloud.tech/api/badges/coop-cloud/recipes.coopcloud.tech/status.svg?ref=refs/heads/main)](https://build.coopcloud.tech/coop-cloud/recipes.coopcloud.tech)
The Co-op Cloud recipes catalogue. Our digital configuration commons, browsable in a simple and pleasant web UI.
@ -33,6 +33,8 @@ __Build command:__ `npm run build`
__Publish directory:__ `public`
Then, run `make` to deploy the new version to `mellor.coopcloud.tech`.
## thanks
created using [`elm-spa`](https://elm-spa.dev)

View File

@ -3,25 +3,28 @@ version: "3.8"
services:
app:
image: "3wordchant/abra-apps:latest"
image: "git.coopcloud.tech/coop-cloud/recipes.coopcloud.tech:latest"
networks:
- proxy
healthcheck:
test: "nodejs -e \"http.get('http://localhost:8000', (res) => { console.log('status: ', res.statusCode); if (res.statusCode == 200) { process.exit(0); } else { process.exit(1); } });\""
interval: 30s
timeout: 10s
retries: 3
start_period: 1m
# healthcheck:
# test: "nodejs -e \"http.get('http://localhost:8000', (res) => { console.log('status: ', res.statusCode); if (res.statusCode == 200) { process.exit(0); } else { process.exit(1); } });\""
# interval: 30s
# timeout: 10s
# retries: 3
# start_period: 1m
deploy:
update_config:
failure_action: rollback
order: start-first
labels:
- "traefik.enable=true"
- "traefik.http.services.abra-apps-dev.loadbalancer.server.port=8000"
- "traefik.http.routers.abra-apps-dev.rule=Host(`recipes.coopcloud.tech`)"
- "traefik.http.routers.abra-apps-dev.entrypoints=web-secure"
- "traefik.http.routers.abra-apps-dev.tls.certresolver=production"
- "traefik.http.services.abra-recipes.loadbalancer.server.port=80"
- "traefik.http.routers.abra-recipes.rule=(Host(`dev.apps.coopcloud.tech`)||Host(`recipes.coopcloud.tech`))"
- "traefik.http.routers.abra-recipes.entrypoints=web-secure"
- "traefik.http.routers.abra-recipes.tls.certresolver=production"
- "traefik.http.routers.abra-recipes.middlewares=abra-recipes-redirect"
- "traefik.http.middlewares.abra-recipes-redirect.headers.SSLForceHost=true"
- "traefik.http.middlewares.abra-recipes-redirect.headers.SSLHost=recipes.coopcloud.tech"
networks:
proxy:

View File

@ -16,6 +16,7 @@
"elm/url": "1.0.0",
"elm-community/json-extra": "4.3.0",
"elm-community/string-extra": "4.0.1",
"fapian/elm-html-aria": "1.4.0",
"pablohirafuji/elm-markdown": "2.0.5"
},
"indirect": {

View File

@ -1,6 +1,6 @@
deploy:
@DOCKER_CONTEXT=mellor.coopcloud.tech \
docker stack rm dev_apps_coopcloud_tech && \
docker stack rm recipes_coopcloud_tech && \
DOCKER_CONTEXT=mellor.coopcloud.tech \
docker stack deploy -c compose.yml dev_apps_coopcloud_tech
docker stack deploy -c compose.yml recipes_coopcloud_tech

17
nginx.conf Normal file
View File

@ -0,0 +1,17 @@
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri /index.html =404;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

560
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -22,14 +22,14 @@
"author": "",
"license": "ISC",
"devDependencies": {
"chokidar-cli": "2.1.0",
"elm": "0.19.1-3",
"chokidar-cli": "3.0.0",
"elm": "0.19.1-6",
"elm-live": "4.0.2",
"elm-spa": "5.0.4",
"elm-test": "0.19.1-revision2",
"npm-run-all": "4.1.5"
},
"dependencies": {
"elm-format": "^0.8.5"
"elm-format": "^0.8.6"
}
}

View File

@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- CSS goes here -->
<link rel="stylesheet" href="/style.css">
<title>abra recipes</title>
<title>Co-op Cloud Recipes</title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<!--<link rel="stylesheet"
@ -20,7 +20,7 @@
<nav class="navbar navbar-expand-lg sticky-top font-weight-bold" style="background: rgb(255, 79, 136) none repeat scroll 0% 0%;">
<a class="navbar-brand text-dark" href="/">
<img src="/logo.png" class="d-inline-block align-top mr-2" alt="" width="30" height="30">
abra recipes</a>
Co-op Cloud Recipes</a>
</nav>
<div class="container-fluid">
<div class="pt-3">
@ -28,7 +28,7 @@
<div class="card">
<div class="card-header">
<h2>
abra recipes</h2>
Co-op Cloud Recipes</h2>
</div>
<div class="card-body">
<p>

View File

@ -29,16 +29,51 @@ i.fas, i.fab {
}
/* Categories */
/* Filtering */
#filter {
position: fixed;
left: 0;
background-color: var(--light-blue);
padding-top: 1rem;
height: 100%;
}
#filter > form > div {
margin: 1rem 0;
}
#filter h3 {
font-size: 18px;
}
input[type=checkbox] {
margin-right: 0.5rem;
}
a.help {
display: inline-block;
margin-left: 0.5rem;
font-size: 14px;
color: var(--dark-pink);
}
.category-tile {
cursor: pointer;
}
.category-tile:hover {
color: var(--dark-blue);
}
.category-tile.active {
color: var(--white);
background-color: var(--light-blue);
border-radius: 5px;
}
/* Intro */
.card#intro {
margin: 1em 0;
}
/* Cards */
@ -46,6 +81,7 @@ i.fas, i.fab {
.app-category {
background-color: var(--light-blue);
color: var(--white);
margin-left: 0.5rem;
}
.card-description {
@ -73,10 +109,14 @@ i.fas, i.fab {
.card-img-top {
width: 100%;
height: 16vw;
height: 5vw;
object-fit: cover;
}
.card-img-large {
height: 10vw;
}
.smaller-card {
border: 1px solid var(--dark-pink);
border-radius: 20px;
@ -95,31 +135,6 @@ i.fas, i.fab {
}
/* Search bar*/
.search-bar-container {
margin: 2em;
display: flex;
flex-flow: row wrap;
align-items: center;
}
.search-bar-input, .search-dropdown {
margin: 0.5em;
height: calc(1.5em + .75rem + 2px);
background-color: var(--white);
border: 1px solid var(--dark-pink);
border-radius: .5rem;
}
.search-bar-input {
width: 30rem;
}
.search-dropdown {
width: 10rem;
}
/* Navbar */
.navbar-text {
color: var(--dark-blue);
@ -132,7 +147,7 @@ i.fas, i.fab {
}
@media (min-width: 768px) {
.card-body p {
.smaller-card .card-body p {
height: 2.5rem;
}
}
@ -141,3 +156,10 @@ i.fas, i.fab {
.card-body p {
}
}
@media (max-width: 768px) {
#filter {
width: 100%;
position: relative;
margin-bottom: 1rem;
}

3
renovate.json Normal file
View File

@ -0,0 +1,3 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}

View File

@ -37,14 +37,15 @@ view { params } =
elm_link = a [ href "https://elm-lang.org/" ] [ text "Elm" ]
coopcloud_link = a [ href "https://coopcloud.tech/" ] [ text "Co-op Cloud" ]
source_link = a [ href "https://git.coopcloud.tech/coop-cloud/abra-apps" ] [ text "source" ]
autonomic_link = a [ href "https://autonomic.zone" ] [ text "Autonomic" ]
in
{ title = "about abra recipes"
{ title = "About Co-op Cloud Recipes"
, body =
[ div [ class "pt-3" ]
[ div [ class "col-md-6 col-sm-10 mb-3 offset-md-3 offset-sm-1" ]
[ div [ class "card" ]
[ div [ class "card-header" ]
[ h2 [] [ text "abra recipes" ]
[ h2 [] [ text "Co-op Cloud Recipes" ]
]
, div [ class "card-body" ]
[ p []
@ -52,7 +53,7 @@ view { params } =
text "a lil' "
, text " tool to display "
, coopcloud_link
, text " apps."
, text " recipes."
]
, p []
[
@ -63,7 +64,9 @@ view { params } =
]
, div [ class "card-footer" ]
[ p []
[ text "by @3wc ("
[ text "made with 🤪 at "
, autonomic_link
, text " ("
, source_link
, text ")"
]

View File

@ -37,9 +37,9 @@ type alias App =
{ name : String
, category : String
, repository : Maybe String
, versions : Maybe (List String)
, versions : List String
, icon : Maybe String
, status : String
, status : Int
, slug : String
, default_branch : String
, website : Maybe String
@ -151,13 +151,13 @@ title : Model -> String
title model =
case model.status of
Loading ->
"loading abra recipes"
"loading Co-op Cloud Recipes"
Failure ->
"error - abra recipes"
"error - Co-op Cloud Recipes"
Success app ->
app.name ++ " abra recipes"
app.name ++ " Co-op Cloud Recipes"
body : Model -> Html Msg
@ -192,23 +192,23 @@ viewStatusBadge app =
let
status_class =
case app.status of
"1" ->
5 ->
"badge-success"
"2" ->
4 ->
"badge-info"
"3" ->
3 ->
"badge-warning"
"4" ->
2 ->
"badge-danger"
_ ->
"badge-dark"
in
span [ class ("card-link badge " ++ status_class) ]
[ text ("Score: " ++ app.status) ]
[ text ("Score: " ++ String.fromInt app.status) ]
viewApp : App -> String -> Html Msg
@ -265,13 +265,16 @@ viewApp app readme =
, repository_link
, website_link
]
, img [ class "card-img-top", src icon_url, alt ("icon for " ++ app.name) ] []
, img [ class "card-img-top card-img-large", src icon_url, alt ("icon for " ++ app.name) ] []
, div [ class "card-body" ]
-- render Markdown with no special options
[ div [] (Markdown.toHtml Nothing readme)
]
, div [ class "card-footer" ]
[]
[ h5 [] [ text "Versions" ]
, ul []
(List.map (\version -> li [] [ text version ]) app.versions)
]
]
]
@ -283,7 +286,7 @@ viewApp app readme =
loadApp : Cmd Msg
loadApp =
Http.get
{ url = "https://apps.coopcloud.tech/"
{ url = "https://recipes.coopcloud.tech/recipes.json"
, expect = Http.expectJson GotApps appListDecoder
}
@ -304,27 +307,37 @@ loadREADME app =
in
Http.get
-- FIXME use live Gitea link
{ url = "https://cors-container.herokuapp.com/https://git.coopcloud.tech/coop-cloud/" ++ app.slug ++ "/raw/branch/" ++ app.default_branch ++ "/README.md"
{ url = "https://git.coopcloud.tech/coop-cloud/" ++ app.slug ++ "/raw/branch/" ++ app.default_branch ++ "/README.md"
, expect = Http.expectString GotText
}
featuresDecoder : Decode.Decoder String
featuresDecoder =
-- get features.status if it's there
Decode.oneOf
[ Decode.at [ "status" ] Decode.string
, Decode.succeed ""
[ Decode.at [ "status" ] Decode.int
, Decode.succeed 5
]
versionsDecoder : Decode.Decoder (List String)
versionsDecoder =
Decode.list (Decode.keyValuePairs Decode.value)
|> Decode.map buildVersions
buildVersions : List (List ( String, Decode.Value )) -> List String
buildVersions versions =
List.concatMap (List.map (\( version, _ ) -> version)) versions
appDecoder : Decode.Decoder App
appDecoder =
Decode.succeed App
|> andMap (Decode.field "name" Decode.string)
|> andMap (Decode.field "category" Decode.string)
|> andMap (Decode.maybe (Decode.field "repository" Decode.string))
|> andMap (Decode.succeed Nothing)
|> andMap (Decode.at [ "versions" ] versionsDecoder)
-- |> andMap (Decode.succeed Nothing)
|> andMap (Decode.maybe (Decode.field "icon" Decode.string))
|> andMap (Decode.at [ "features" ] featuresDecoder)
|> andMap (Decode.succeed "")

View File

@ -1,8 +1,9 @@
module Pages.Top exposing (Model, Msg, Params, page)
import Enum exposing (Enum)
import Html exposing (Html, a, button, div, h2, h5, i, img, li, p, span, text, ul, form, label, select, option, input)
import Html.Attributes exposing (alt, class, href, src, style, id, for, value)
import Html exposing (Html, a, button, div, form, h2, h3, h5, i, img, input, label, li, option, p, select, span, text, ul)
import Html.Attributes exposing (alt, class, classList, for, href, id, src, style, target, type_, value)
import Html.Attributes.Aria exposing (ariaLabel)
import Html.Events exposing (onClick, onInput)
import Http
import Json.Decode as Decode
@ -26,6 +27,7 @@ page =
}
-- INIT
@ -52,8 +54,8 @@ type alias Model =
, filter_category : Maybe Category
, filter_text : Maybe String
, status : Status
, apps : (List App)
, results : (List App)
, apps : List App
, results : List App
}
@ -74,14 +76,13 @@ type Category
categories : Enum Category
categories =
Enum.create
[ ( "Apps", Apps )
[ ( "(Everything)", All )
, ( "Apps", Apps )
, ( "Utilities", Utilities )
, ( "Development", Development )
, ("All", All)
]
init : Url Params -> ( Model, Cmd Msg )
init { params } =
( default_model, loadApps )
@ -94,8 +95,14 @@ default_image =
default_model : Model
default_model =
{ filter_score = Nothing, filter_category = Nothing, filter_text = Nothing,
status = Loading, apps = [], results = [] }
{ filter_score = Nothing
, filter_category = Nothing
, filter_text = Nothing
, status = Loading
, apps = []
, results = []
}
-- UPDATE
@ -113,41 +120,55 @@ filterAppsScore : List App -> Maybe Int -> List App
filterAppsScore apps score =
case score of
Just s ->
List.filter (\app ->
app.status <= s
) apps
List.filter
(\app ->
app.status >= s
)
apps
Nothing ->
apps
filterAppsCategory : List App -> Maybe Category -> List App
filterAppsCategory apps category =
case category of
Just c ->
if c == All then
apps
else
List.filter (\app ->
List.filter
(\app ->
app.category == categories.toString c
) apps
)
apps
Nothing ->
apps
filterAppsText : List App -> Maybe String -> List App
filterAppsText apps text =
case text of
Just "" ->
apps
Just t ->
List.filter (\app ->
String.contains (String.toLower t) (
String.toLower app.name ++ String.toLower (
Maybe.withDefault "" app.description
List.filter
(\app ->
String.contains (String.toLower t)
(String.toLower app.name
++ String.toLower
(Maybe.withDefault "" app.description)
)
)
) apps
apps
Nothing ->
apps
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
@ -156,39 +177,53 @@ update msg model =
FilterScore filter ->
let
filter_score = String.toInt filter
filter_score =
String.toInt filter
in
( { model
| filter_score = filter_score
, results = filterAppsScore (
filterAppsCategory (
filterAppsText model.apps model.filter_text
) model.filter_category
) (String.toInt filter)
}, Cmd.none )
, results =
filterAppsScore
(filterAppsCategory
(filterAppsText model.apps model.filter_text)
model.filter_category
)
(String.toInt filter)
}
, Cmd.none
)
FilterCategory filter ->
let
category = categories.fromString filter
category =
categories.fromString filter
in
( { model
| filter_category = category
, results = filterAppsCategory (
filterAppsScore (
filterAppsText model.apps model.filter_text
)model.filter_score
) category
}, Cmd.none )
, results =
filterAppsCategory
(filterAppsScore
(filterAppsText model.apps model.filter_text)
model.filter_score
)
category
}
, Cmd.none
)
FilterText filter ->
( { model
| filter_text = Just filter
, results = filterAppsText (
filterAppsScore (
filterAppsCategory model.apps model.filter_category
) model.filter_score
) (Just filter)
}, Cmd.none )
, results =
filterAppsText
(filterAppsScore
(filterAppsCategory model.apps model.filter_category)
model.filter_score
)
(Just filter)
}
, Cmd.none
)
GotApps result ->
case result of
@ -196,11 +231,17 @@ update msg model =
( { default_model
| status = Success
, apps = apps
, results = apps }, Cmd.none )
, results = apps
}
, Cmd.none
)
Err _ ->
( { default_model
| status = Failure}, Cmd.none )
| status = Failure
}
, Cmd.none
)
subscriptions : Model -> Sub Msg
@ -214,14 +255,14 @@ subscriptions model =
view : Model -> Document Msg
view model =
{ title = "abra recipes"
{ title = "Co-op Cloud Recipes"
, body = [ body model ]
}
body : Model -> Html Msg
body model =
div [ class "pt-3" ]
div []
[ viewApps model
]
@ -231,16 +272,16 @@ viewStatusBadge app =
let
status_class =
case app.status of
1 ->
5 ->
"badge-success"
2 ->
4 ->
"badge-info"
3 ->
"badge-warning"
4 ->
2 ->
"badge-danger"
_ ->
@ -303,16 +344,21 @@ viewApp app =
, p [ class "card-description" ] [ text (ellipsis 100 (withDefault "" app.description)) ]
]
, div [ class "footer" ]
[ span [ class "badge app-category" ] [ text app.category ]]
[ viewStatusBadge app, span [ class "badge app-category" ] [ text app.category ] ]
]
]
viewCategories : (String, Category) -> Html Msg
viewCategories category =
div [ class "category-tile", onClick (FilterCategory (Tuple.first category)) ] [text (Tuple.first category)]
viewCategory : Model -> ( String, Category ) -> Html Msg
viewCategory model category =
div
[ classList
[ ( "category-tile", True )
, ( "active", categories.toString (Maybe.withDefault All model.filter_category) == Tuple.first category )
]
, onClick (FilterCategory (Tuple.first category))
]
[ text (Tuple.first category) ]
viewApps : Model -> Html Msg
@ -335,36 +381,63 @@ viewApps model =
Success ->
div [ class "row justify-content-center" ]
[ div [ class "col-md-3" ] [
h2 [ class "app-headings" ] [text "Categories"]
, div [] (List.map viewCategories categories.list)
[ div [ class "col-md-3", id "filter" ]
[ h2 [ class "app-headings" ] [ text "Finding things" ]
, form []
[ div []
[ h3 [] [ text "Search" ]
, input [ ariaLabel "search", id "text", onInput FilterText ] []
]
, div [ class "col-md-6" ]
, div []
[ h3 [] [ text "Categories" ]
, div [] (List.map (viewCategory model) categories.list)
]
, div []
[ h3 [] [ text "Status" ]
, div []
[ label [] [ text "Minimum score: " ]
, a [ class "help", target "_blank", href "https://docs.coopcloud.tech/abra/recipes/#status-features-score" ] [ text "(help)" ]
]
, select [ class "search-dropdown", id "level", onInput FilterScore ]
[ option [] [ text "any" ]
, option [ value "5" ] [ text "5 (amazing)" ]
, option [ value "4" ] [ text "4 (good)" ]
, option [ value "3" ] [ text "3 (ok)" ]
, option [ value "2" ] [ text "2 (basic)" ]
, option [ value "1" ] [ text "1 (chaos)" ]
]
]
]
]
, div [ class "col-md-6 offset-md-3" ]
[ div [ class "row" ]
[ div [ class "col-sm-12" ] [
div [] [
form [ class "search-bar-container" ] [
label [ for "text" ] [ text "Search" ]
, input [ class "search-bar-input", id "text", onInput FilterText ] []
, label [ for "level" ] [ text " and show only items that have at least " ]
, select [ class "search-dropdown", id "level", onInput FilterScore ] [
option [ ] [ text "any" ]
, option [ value "1" ] [ text "1 (production)" ]
, option [ value "2" ] [ text "2 (beta)" ]
, option [ value "3" ] [ text "3 (alpha)" ]
, option [ value "4" ] [ text "4 (pre-alpha)" ]
]
, text "builds "
[ div [ class "col-sm-12" ]
[ div []
[]
]
]
, div [ id "intro", class "card" ]
[ div [ class "card-body" ]
[ h2 [ class "app-headings card-title" ] [ text "Co-op Cloud Recipes" ]
, text "You can use these recipes ("
, a
[ href
"https://docs.coopcloud.tech/intro/glossary/#recipe"
]
[ text "What's a recipe?"
]
, text ") with "
, a [ href "https://coopcloud.tech" ]
[ text "Co-op Cloud"
]
, text "."
]
]
, h2 [ class "app-headings" ] [ text "Apps" ]
, div [ class "row" ]
(List.map viewApp
(model.results
|> List.sortWith
(by .status ASC
(by .status DESC
|> andThen (String.toLower << .name) ASC
)
)
@ -373,14 +446,21 @@ viewApps model =
, div [ class "col-md-3" ] []
]
-- HTTP
loadApps : Cmd Msg
loadApps =
Http.get
{ url = "https://apps.coopcloud.tech/"
Http.request
{ url = "https://recipes.coopcloud.tech/recipes.json"
, expect = Http.expectJson GotApps appListDecoder
, headers = [ Http.header "Content-Type" "application/json" ]
, body = Http.emptyBody
, method = "GET"
, timeout = Nothing
, tracker = Nothing
}

View File

@ -70,15 +70,15 @@ view { page, toMsg } model =
, body =
[ div [ class "background" ]
[ nav
[ class "navbar navbar-expand-lg sticky-top font-weight-bold" ]
[ a [ class "navbar-text", href (Route.toString Route.Top) ]
[ class "navbar navbar-expand-lg sticky-top" ]
[ a [ class "font-weight-bold navbar-text", href (Route.toString Route.Top) ]
[ img
[ src "/logo-2.png"
, class "d-inline-block align-top mr-2"
, alt ""
, width 48
, height 16 ] []
, text "abra recipes"
, text "Co-op Cloud Recipes"
]
, ul [ class "navbar-nav" ]
[ li [ class "nav-tem" ] [ a [ class "nav-link navbar-text", href (Route.toString Route.About) ] [ text "about" ] ]