« get me outta code hell

link.js « util « src - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/util/link.js
blob: ee3579d553d4ded0fdd0ed06a56b50e7c6f480af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/** @format */

// This file is essentially one level of a8straction a8ove urls.js (and the
// urlSpec it gets its paths from). It's a 8unch of utility functions which
// take certain types of wiki data o8jects (colloquially known as "things")
// and return actual <a href> HTML link tags.
//
// The functions we're cre8ting here (all factory-style) take a "to" argument,
// which is roughly a function which takes a urlSpec key and spits out a path
// to 8e stuck in an href or src or suchever. There are also a few other
// options availa8le in all the functions, making a common interface for
// gener8ting just a8out any link on the site.

import * as html from './html.js';
import {getColors} from './colors.js';

export function getLinkThemeString(color) {
  if (!color) return '';

  const {primary, dim} = getColors(color);
  return `--primary-color: ${primary}; --dim-color: ${dim}`;
}

const appendIndexHTMLRegex = /^(?!https?:\/\/).+\/$/;

const linkHelper =
  (hrefFn, {color = true, attr = null} = {}) =>
  (
    thing,
    {
      to,
      text = '',
      attributes = null,
      class: className = '',
      color: color2 = true,
      hash = '',
    }
  ) => {
    let href = hrefFn(thing, {to});

    if (link.globalOptions.appendIndexHTML) {
      if (appendIndexHTMLRegex.test(href)) {
        href += 'index.html';
      }
    }

    if (hash) {
      href += (hash.startsWith('#') ? '' : '#') + hash;
    }

    return html.tag(
      'a',
      {
        ...(attr ? attr(thing) : {}),
        ...(attributes ? attributes : {}),
        href,
        style:
          typeof color2 === 'string'
            ? getLinkThemeString(color2)
            : color2 && color
            ? getLinkThemeString(thing.color)
            : '',
        class: className,
      },
      text || thing.name
    );
  };

const linkDirectory = (key, {expose = null, attr = null, ...conf} = {}) =>
  linkHelper((thing, {to}) => to('localized.' + key, thing.directory), {
    attr: (thing) => ({
      ...(attr ? attr(thing) : {}),
      ...(expose ? {[expose]: thing.directory} : {}),
    }),
    ...conf,
  });

const linkPathname = (key, conf) =>
  linkHelper(({directory: pathname}, {to}) => to(key, pathname), conf);
const linkIndex = (key, conf) =>
  linkHelper((_, {to}) => to('localized.' + key), conf);

const link = {
  globalOptions: {
    // This should usually only 8e used during development! It'll take any
    // href that ends with `/` and append `index.html` to the returned
    // value (for to.thing() functions). This is handy when developing
    // without a local server (i.e. using file:// protocol URLs in your
    // 8rowser), 8ut isn't guaranteed to 8e 100% 8ug-free.
    appendIndexHTML: false,
  },

  album: linkDirectory('album'),
  albumCommentary: linkDirectory('albumCommentary'),
  artist: linkDirectory('artist', {color: false}),
  artistGallery: linkDirectory('artistGallery', {color: false}),
  commentaryIndex: linkIndex('commentaryIndex', {color: false}),
  flashIndex: linkIndex('flashIndex', {color: false}),
  flash: linkDirectory('flash'),
  groupInfo: linkDirectory('groupInfo'),
  groupGallery: linkDirectory('groupGallery'),
  home: linkIndex('home', {color: false}),
  listingIndex: linkIndex('listingIndex'),
  listing: linkDirectory('listing'),
  newsIndex: linkIndex('newsIndex', {color: false}),
  newsEntry: linkDirectory('newsEntry', {color: false}),
  staticPage: linkDirectory('staticPage', {color: false}),
  tag: linkDirectory('tag'),
  track: linkDirectory('track', {expose: 'data-track'}),

  // TODO: This is a bit hacky. Files are just strings (not objects), so we
  // have to manually provide the album alongside the file. They also don't
  // follow the usual {name: whatever} type shape, so we have to provide that
  // ourselves.
  _albumAdditionalFileHelper: linkHelper(
    (fakeFileObject, {to}) =>
      to(
        'media.albumAdditionalFile',
        fakeFileObject.album.directory,
        fakeFileObject.name
      ),
    {color: false}
  ),
  albumAdditionalFile: ({file, album}, {to}) =>
    link._albumAdditionalFileHelper(
      {
        name: file,
        album,
      },
      {to}
    ),

  media: linkPathname('media.path', {color: false}),
  root: linkPathname('shared.path', {color: false}),
  data: linkPathname('data.path', {color: false}),
  site: linkPathname('localized.path', {color: false}),
};

export default link;