stuff
This commit is contained in:
commit
f053fd4420
BIN
data/banner.png
Executable file
BIN
data/banner.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
1
data/pages/about.md
Normal file
1
data/pages/about.md
Normal file
@ -0,0 +1 @@
|
||||
I promise I'm not as bad at writing code as I am at writing about pages
|
33
data/pages/home.md
Normal file
33
data/pages/home.md
Normal file
@ -0,0 +1,33 @@
|
||||
# notgne2's pages
|
||||
|
||||
## 🍆 ...
|
||||
|
||||
Passionate shitposter and software engineer.
|
||||
|
||||
Sometimes I have posts [here](/posts/).
|
||||
|
||||
## Some recent projects
|
||||
|
||||
- Rustchan - Fully featured imageboard written in Rust (I actually just lost the link, some other dude maintains it now iirc)
|
||||
- [flup](https://github.com/notgne2/flup) - Pomf compliant file hosting website written in Rust
|
||||
- [LibreBasics](/posts/librebasics) - experiments using FreeBasics freely
|
||||
- [ViveAHK](/posts/viveahk) - Allows you to bind keys to Vive controller keypresses
|
||||
- comet protocol - im not telling u nuffing yet
|
||||
- i will always forget to update this
|
||||
|
||||
|
||||
## My work
|
||||
|
||||
I have worked significant amounts on various projects, most recently being:
|
||||
|
||||
- [gm8.app](https://gm8.app) - Buy, deploy and manage servers from Discord
|
||||
- [EdenJS](https://github.com/eden-js/cli) - Awesome isomorphic NodeJS skeleton for structured applications
|
||||
- [DiscordBots](https://discordbots.org/) - Popular index of Discord bots and servers
|
||||
- [Tox](https://tox.chat) - FOSS Secure messaging application
|
||||
|
||||
## Contact me
|
||||
|
||||
- Skype: [evilaubergine](skype:evilaubergine)
|
||||
- Rizon/Freenode: [notgne2](#)
|
||||
- Email: [gen2@gen2.space](mailto:gen2@gen2.space)
|
||||
- Discord: [notgne2#0240](#)
|
37
data/pages/posts/librebasics.md
Normal file
37
data/pages/posts/librebasics.md
Normal file
@ -0,0 +1,37 @@
|
||||
Librebasics is a small project of mine to get free internet on FreeBasics internet connections provided by FaceBook available primarily in India, Thailand, and developing African nations. It's currently in a very early stage, but I will constantly update this page with information I gather about their DPI (Deep Packet Inspection) as time goes on, along with my methods for evasion.
|
||||
|
||||
## Why
|
||||
When I wrote this, I was stuck in Thailand , where one of the primary mobile providers has FreeBasics by default if you run out of credit, so I naturally decided to find a way around that.
|
||||
|
||||
## Current observations
|
||||
Their DPI is very strict, appearing to possibly check HTTPS certificates, and check both the request headers and responses of all HTTP connections, other protocols will be strictly disallowed, and other ports other than 443/80 blocked (mostly?? TODO: investigate this)
|
||||
|
||||
I am not sure if this is to do with time or location, but previously when I have been limited to Facebook-only access on TrueMove, it has not taken me through FreeBasics, and during this time, Facebook chat and calling was not available. When audio/video calls is possible it would be a good idea to attempt tunneling data over the webrtc connection which is established, or perhaps even fool the DPI and start my own connection (I do not know much about webrtc, or how Facebook uses it).
|
||||
|
||||
The main rules I have found are...
|
||||
- Request URL is relative, or a FreeBasics-permitted
|
||||
- `Host` header is a FreeBasics-permitted URL
|
||||
- Response is not longer than specified (this varies ??)
|
||||
- `0.freebasics.com` rules are
|
||||
- - Path is `/?ref=zerobalance`
|
||||
- - Requests following these rules are allowed
|
||||
- All other site rules are
|
||||
- - Unknown, requests following only previous rules are disallowed
|
||||
|
||||
## Current method
|
||||
God, I feel like a Javascript developer explaining his amazing stack of lossy databases and frontend frameworks right now but, here is how I am currently bypassing FreeBasics.
|
||||
|
||||
1. "slowngay™" tunnel, making requests into "Facebook friendly" requests, and converting back on the other end
|
||||
2. HTTP tunnel, I am using [Crowbar](https://github.com/q3k/crowbar), as many use methods which do not play nice with either my tunnel or the DPI
|
||||
3. SSH connection over the tunnel, opening a local socks proxy with `-D`
|
||||
4. [redsocks](http://darkk.net.ru/redsocks/) and iptables for routing traffic though the proxy
|
||||
|
||||
## Phone usage
|
||||
While this may sound unusually complicated, it is quite simple to make this work straight on a phone, without a any computer (you will need root, of course)
|
||||
|
||||
To make this work on my phone I used Termux, and ProxyDroid. Termux was really the main piece in making this setup so easy, it is a very useful tool. Crowbar as mentioned before can compile in an android shell with no configuration, in Termux just run `apt install golang`, then `go get` the repo.
|
||||
|
||||
To make this even easier and cooler to use after it has been set up, try installing `Termux:Widget`, so you can have a stop and start shortcut for the proxy tunnel components on your home screen, along with the proxy toggle widget available from ProxyDroid.
|
||||
|
||||
## Where is your software m8?
|
||||
Well, once I have an array of good bypass methods, I may package this and sell it. Of course I will not hold back information from any tech literate people who are interested, but I'm still not going to baby you by giving you my 30 line long Node.js script I used to replace the headers (PS. they don't filter "X-" headers), just write one yourself in a not so garbage language.
|
51
data/pages/posts/viveahk.md
Normal file
51
data/pages/posts/viveahk.md
Normal file
@ -0,0 +1,51 @@
|
||||
### (or: tool assisted smugging)
|
||||
|
||||
When I got my HTC Vive Pro I was disappointed at the lack of script-ability when it came to automation or really any kind of programatic hook, and scouring Reddit only found me a tool for using the Oculus Rift through AHK, which seemed unfair especially given it's extreme inferiority. This greatly annoyed me, given how badly I needed to make a shortcut to start and stop recording in ShareX to assist me in smugging on people who make better financial choices than me, so I made this.
|
||||
|
||||
Searching around on Google eventually found me [this](https://gist.github.com/awesomebytes/75daab3adb62b331f21ecf3a03b3ab46), a script able to get HTC Vive controller inputs live, and print the events, so I quickly augmented this with the python win32api to emulate keypresses, and much to my surprise it worked perfectly, so far I've already completed my initial goal of taking screenshots and videos with ShareX entirely from VR, and will soon move on to making more smugging tools through controller shortcuts.
|
||||
|
||||
```python
|
||||
pressed = {}
|
||||
|
||||
def take_press(set_side, set_key, set_value, set_keycode, data):
|
||||
if data['side'] == set_side and data[set_key] == set_value and not pressed.get(hex(set_keycode)):
|
||||
pressed[hex(set_keycode)] = True
|
||||
win32api.keybd_event(set_keycode, 0, 0, 0)
|
||||
elif data['side'] == set_side and data[set_key] != set_value and pressed.get(hex(set_keycode)):
|
||||
pressed[hex(set_keycode)] = False
|
||||
win32api.keybd_event(set_keycode, 0 ,win32con.KEYEVENTF_KEYUP ,0)
|
||||
|
||||
def handle_input(data):
|
||||
take_press('left', 'grip_button', True, 0x88, data)
|
||||
take_press('right', 'grip_button', True, 0x89, data)
|
||||
take_press('left', 'trigger', 1, 0x8A, data)
|
||||
take_press('right', 'trigger', 1, 0x8B, data)
|
||||
take_press('left', 'menu_button', True, 0x8C, data)
|
||||
take_press('right', 'menu_button', True, 0x8D, data)
|
||||
take_press('left', 'trackpad_pressed', True, 0x8E, data)
|
||||
take_press('right', 'trackpad_pressed', True, 0x8F, data)
|
||||
take_press('left', 'trackpad_touched', True, 0x92, data)
|
||||
take_press('right', 'trackpad_touched', True, 0x93, data)
|
||||
```
|
||||
|
||||
You can use the virtual keypresses in anything, besides a few applications that won't recognize it as a shortcut due to the keycodes not being registered to anything.
|
||||
|
||||
An example of usage would be this simple AutoHotKey script, which will activate if you press right menu, left grip, and right grip, and will run an awkwardly long key combination you might want to bind in ShareX.
|
||||
|
||||
```
|
||||
~vk0x88 & ~vk0x89::
|
||||
If GetKeyState("vk0x8D") {
|
||||
Send, {Control down}
|
||||
Send, {Shift down}
|
||||
Send, {Alt down}
|
||||
Send, {LWin down}
|
||||
Send, {p down}
|
||||
Send, {p up}
|
||||
Send, {Control up}
|
||||
Send, {Shift up}
|
||||
Send, {Alt up}
|
||||
Send, {LWin up}
|
||||
}
|
||||
```
|
||||
|
||||
If you're actually interested in my finished script, see [this gist](https://gist.github.com/notgne2/833ce83c9bf9f8034a4c8c11ab3d16e2)
|
11
default.nix
Normal file
11
default.nix
Normal file
@ -0,0 +1,11 @@
|
||||
{ callPackage, ... }:
|
||||
|
||||
with (callPackage (builtins.fetchGit {
|
||||
url = https://git.wizbos.club/wizbos-pub/wand-front-utils.git;
|
||||
rev = "c05fd94028d6023b3d4debf0c1d2bece2c547df5";
|
||||
}) {});
|
||||
mkWandardFront {
|
||||
src = ./.;
|
||||
name = "gen2.space";
|
||||
routes = [ "/" "/about" "/404" "/posts" "/posts/viveahk" "/posts/librebasics" ];
|
||||
}
|
72
elm-srcs.nix
Normal file
72
elm-srcs.nix
Normal file
@ -0,0 +1,72 @@
|
||||
{
|
||||
|
||||
"mdgriffith/elm-ui" = {
|
||||
sha256 = "17iayf13r5fy38xlliaizi6af12jp1yw2vjxyhi6qf16xy579vn8";
|
||||
version = "1.1.5";
|
||||
};
|
||||
|
||||
"elm/html" = {
|
||||
sha256 = "1n3gpzmpqqdsldys4ipgyl1zacn0kbpc3g4v3hdpiyfjlgh8bf3k";
|
||||
version = "1.0.0";
|
||||
};
|
||||
|
||||
"elm/browser" = {
|
||||
sha256 = "0nagb9ajacxbbg985r4k9h0jadqpp0gp84nm94kcgbr5sf8i9x13";
|
||||
version = "1.0.2";
|
||||
};
|
||||
|
||||
"dillonkearns/elm-markdown" = {
|
||||
sha256 = "08l0ml9qq6qif98ka40ixx99b7gravmacskw0h4zzrzv2n9va3vl";
|
||||
version = "1.1.3";
|
||||
};
|
||||
|
||||
"elm/core" = {
|
||||
sha256 = "1l0qdbczw91kzz8sx5d5zwz9x662bspy7p21dsr3f2rigxiix2as";
|
||||
version = "1.0.2";
|
||||
};
|
||||
|
||||
"elm/url" = {
|
||||
sha256 = "0av8x5syid40sgpl5vd7pry2rq0q4pga28b4yykn9gd9v12rs3l4";
|
||||
version = "1.0.0";
|
||||
};
|
||||
|
||||
"elm/http" = {
|
||||
sha256 = "008bs76mnp48b4dw8qwjj4fyvzbxvlrl4xpa2qh1gg2kfwyw56v1";
|
||||
version = "2.0.0";
|
||||
};
|
||||
|
||||
"elm/bytes" = {
|
||||
sha256 = "02ywbf52akvxclpxwj9n04jydajcbsbcbsnjs53yjc5lwck3abwj";
|
||||
version = "1.0.8";
|
||||
};
|
||||
|
||||
"elm/file" = {
|
||||
sha256 = "1rljcb41dl97myidyjih2yliyzddkr2m7n74x7gg46rcw4jl0ny8";
|
||||
version = "1.0.5";
|
||||
};
|
||||
|
||||
"elm/json" = {
|
||||
sha256 = "0kjwrz195z84kwywaxhhlnpl3p251qlbm5iz6byd6jky2crmyqyh";
|
||||
version = "1.1.3";
|
||||
};
|
||||
|
||||
"rtfeldman/elm-hex" = {
|
||||
sha256 = "1y0aa16asvwdqmgbskh5iba6psp43lkcjjw9mgzj3gsrg33lp00d";
|
||||
version = "1.0.0";
|
||||
};
|
||||
|
||||
"elm/parser" = {
|
||||
sha256 = "0a3cxrvbm7mwg9ykynhp7vjid58zsw03r63qxipxp3z09qks7512";
|
||||
version = "1.1.0";
|
||||
};
|
||||
|
||||
"elm/time" = {
|
||||
sha256 = "0vch7i86vn0x8b850w1p69vplll1bnbkp8s383z7pinyg94cm2z1";
|
||||
version = "1.0.0";
|
||||
};
|
||||
|
||||
"elm/virtual-dom" = {
|
||||
sha256 = "0q1v5gi4g336bzz1lgwpn5b1639lrn63d8y6k6pimcyismp2i1yg";
|
||||
version = "1.0.2";
|
||||
};
|
||||
}
|
31
elm.json
Normal file
31
elm.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"type": "application",
|
||||
"source-directories": [
|
||||
"src"
|
||||
],
|
||||
"elm-version": "0.19.0",
|
||||
"dependencies": {
|
||||
"direct": {
|
||||
"dillonkearns/elm-markdown": "1.1.3",
|
||||
"elm/browser": "1.0.2",
|
||||
"elm/core": "1.0.2",
|
||||
"elm/html": "1.0.0",
|
||||
"elm/http": "2.0.0",
|
||||
"elm/url": "1.0.0",
|
||||
"mdgriffith/elm-ui": "1.1.5"
|
||||
},
|
||||
"indirect": {
|
||||
"elm/bytes": "1.0.8",
|
||||
"elm/file": "1.0.5",
|
||||
"elm/json": "1.1.3",
|
||||
"elm/parser": "1.1.0",
|
||||
"elm/time": "1.0.0",
|
||||
"elm/virtual-dom": "1.0.2",
|
||||
"rtfeldman/elm-hex": "1.0.0"
|
||||
}
|
||||
},
|
||||
"test-dependencies": {
|
||||
"direct": {},
|
||||
"indirect": {}
|
||||
}
|
||||
}
|
23
package.json
Normal file
23
package.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@prerenderer/renderer-jsdom": "^0.2.0",
|
||||
"copy-webpack-plugin": "^5.1.0",
|
||||
"elm-webpack-loader": "^6.0.1",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"jsdom": "^15.2.1",
|
||||
"prerender-spa-plugin": "^3.4.0",
|
||||
"tempy": "^0.3.0",
|
||||
"webpack": "^4.41.2",
|
||||
"webpack-cli": "^3.3.10",
|
||||
"workbox-webpack-plugin": "^4.3.1"
|
||||
},
|
||||
"name": "gen2-space",
|
||||
"version": "1.0.0",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "notgne2",
|
||||
"license": "AGPL-3.0",
|
||||
"description": ""
|
||||
}
|
5029
pnpm-lock.yaml
generated
Normal file
5029
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
127
src/MParser.elm
Normal file
127
src/MParser.elm
Normal file
@ -0,0 +1,127 @@
|
||||
module MParser exposing (ezmd)
|
||||
|
||||
import Element exposing (..)
|
||||
import Element.Background
|
||||
import Element.Border
|
||||
import Element.Font as Font
|
||||
import Html.Attributes
|
||||
import Markdown.Html
|
||||
import Markdown.Parser
|
||||
import SiteComponents exposing (..)
|
||||
|
||||
|
||||
ezmd input =
|
||||
case markdownView input of
|
||||
Ok rendered ->
|
||||
Element.column [ Element.spacing 30 ] rendered
|
||||
|
||||
Err errors ->
|
||||
Element.text errors
|
||||
|
||||
|
||||
markdownView : String -> Result String (List (Element msg))
|
||||
markdownView markdown =
|
||||
markdown
|
||||
|> Markdown.Parser.parse
|
||||
|> Result.mapError (\error -> error |> List.map Markdown.Parser.deadEndToString |> String.join "\n")
|
||||
|> Result.andThen (Markdown.Parser.render renderer)
|
||||
|
||||
|
||||
renderer : Markdown.Parser.Renderer (Element msg)
|
||||
renderer =
|
||||
{ heading = heading
|
||||
, raw = Element.paragraph [ Element.spacing 15 ]
|
||||
, thematicBreak = Element.none
|
||||
, plain = Element.text
|
||||
, bold = \content -> Element.row [ Font.bold ] [ Element.text content ]
|
||||
, italic = \content -> Element.row [ Font.italic ] [ Element.text content ]
|
||||
, code = code
|
||||
, link =
|
||||
\{ destination } body ->
|
||||
(if List.member (String.left 1 destination) [ "#", "/" ] then
|
||||
Element.link
|
||||
|
||||
else
|
||||
Element.newTabLink
|
||||
)
|
||||
[ Element.htmlAttribute (Html.Attributes.style "display" "inline-flex") ]
|
||||
{ url = destination
|
||||
, label = Element.paragraph [ Font.color basedGreen, Font.underline ] body
|
||||
}
|
||||
|> Ok
|
||||
, image =
|
||||
\image body ->
|
||||
Element.image [ Element.width Element.fill ] { src = image.src, description = body }
|
||||
|> Ok
|
||||
, list =
|
||||
\items ->
|
||||
Element.column [ Element.spacing 15 ]
|
||||
(items
|
||||
|> List.map
|
||||
(\itemBlocks ->
|
||||
Element.row [ Element.spacing 5 ]
|
||||
[ Element.el
|
||||
[ Element.alignTop ]
|
||||
(Element.text "•")
|
||||
, itemBlocks
|
||||
]
|
||||
)
|
||||
)
|
||||
, codeBlock = codeBlock
|
||||
, html = Markdown.Html.oneOf []
|
||||
}
|
||||
|
||||
|
||||
rawTextToId rawText =
|
||||
rawText
|
||||
|> String.toLower
|
||||
|> String.replace " " "-"
|
||||
|
||||
|
||||
heading : { level : Int, rawText : String, children : List (Element msg) } -> Element msg
|
||||
heading { level, rawText, children } =
|
||||
let
|
||||
fontSize =
|
||||
case level of
|
||||
1 ->
|
||||
36
|
||||
|
||||
2 ->
|
||||
24
|
||||
|
||||
_ ->
|
||||
20
|
||||
in
|
||||
paragraph
|
||||
[ Element.htmlAttribute (Html.Attributes.attribute "name" (rawTextToId rawText))
|
||||
, Element.htmlAttribute (Html.Attributes.id (rawTextToId rawText))
|
||||
, width fill
|
||||
, height shrink
|
||||
, padding 10
|
||||
, greenLines
|
||||
, Font.size fontSize
|
||||
]
|
||||
children
|
||||
|
||||
|
||||
code : String -> Element msg
|
||||
code snippet =
|
||||
Element.el
|
||||
[ Element.Background.color (Element.rgba 0 0 0 0.04)
|
||||
, scrollbars
|
||||
, Element.Border.rounded 2
|
||||
, Element.paddingXY 5 3
|
||||
]
|
||||
(Element.text snippet)
|
||||
|
||||
|
||||
codeBlock : { body : String, language : Maybe String } -> Element msg
|
||||
codeBlock details =
|
||||
Element.el
|
||||
[ Element.Background.color (Element.rgba 0 0 0 0.03)
|
||||
, scrollbars
|
||||
, Element.htmlAttribute (Html.Attributes.style "white-space" "pre")
|
||||
, Element.padding 20
|
||||
, Element.width Element.fill
|
||||
]
|
||||
(Element.text details.body)
|
269
src/Main.elm
Normal file
269
src/Main.elm
Normal file
@ -0,0 +1,269 @@
|
||||
module Main exposing (main)
|
||||
|
||||
import Browser
|
||||
import Browser.Navigation as Nav
|
||||
import Dict exposing (Dict)
|
||||
import Element exposing (..)
|
||||
import Element.Font as Font
|
||||
import Http
|
||||
import List
|
||||
import MParser exposing (ezmd)
|
||||
import SiteComponents exposing (..)
|
||||
import Url
|
||||
import Url.Parser exposing ((</>), Parser)
|
||||
|
||||
|
||||
|
||||
-- MAIN
|
||||
|
||||
|
||||
main : Program () Model Msg
|
||||
main =
|
||||
Browser.application
|
||||
{ init = init
|
||||
, view = view
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
, onUrlChange = UrlChanged
|
||||
, onUrlRequest = LinkClicked
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- MODEL
|
||||
|
||||
|
||||
routeParser : Parser (Route -> a) a
|
||||
routeParser =
|
||||
Url.Parser.oneOf
|
||||
[ Url.Parser.map Home Url.Parser.top
|
||||
, Url.Parser.map Posts (Url.Parser.s "posts")
|
||||
, Url.Parser.map Post (Url.Parser.s "posts" </> Url.Parser.string)
|
||||
, Url.Parser.map About (Url.Parser.s "about")
|
||||
]
|
||||
|
||||
|
||||
routeFromUrl : Url.Url -> Route
|
||||
routeFromUrl url =
|
||||
Maybe.withDefault NotFound (Url.Parser.parse routeParser url)
|
||||
|
||||
|
||||
type Route
|
||||
= Home
|
||||
| Posts
|
||||
| Post String
|
||||
| About
|
||||
| NotFound
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ key : Nav.Key
|
||||
, route : Route
|
||||
, sources : Dict String String
|
||||
}
|
||||
|
||||
|
||||
fetchPage pageName =
|
||||
Http.get
|
||||
{ url = "/data/pages/" ++ pageName ++ ".md"
|
||||
, expect = Http.expectString (GotSrc pageName)
|
||||
}
|
||||
|
||||
|
||||
init : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
|
||||
init _ url key =
|
||||
( { key = key, route = routeFromUrl url, sources = Dict.empty }
|
||||
, Cmd.batch
|
||||
[ fetchPage "home"
|
||||
, fetchPage "about"
|
||||
, fetchPage "posts/viveahk"
|
||||
, fetchPage "posts/librebasics"
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- UPDATE
|
||||
|
||||
|
||||
nameFromRoute route =
|
||||
case route of
|
||||
Home ->
|
||||
"home"
|
||||
|
||||
About ->
|
||||
"about"
|
||||
|
||||
Posts ->
|
||||
"posts"
|
||||
|
||||
Post name ->
|
||||
"post " ++ name
|
||||
|
||||
NotFound ->
|
||||
"404"
|
||||
|
||||
|
||||
type Msg
|
||||
= LinkClicked Browser.UrlRequest
|
||||
| UrlChanged Url.Url
|
||||
| GotSrc String (Result Http.Error String)
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
LinkClicked urlRequest ->
|
||||
case urlRequest of
|
||||
Browser.Internal url ->
|
||||
( model, Nav.pushUrl model.key (Url.toString url) )
|
||||
|
||||
Browser.External href ->
|
||||
( model, Nav.load href )
|
||||
|
||||
UrlChanged url ->
|
||||
( { model | route = routeFromUrl url }, Cmd.none )
|
||||
|
||||
GotSrc pageName result ->
|
||||
case result of
|
||||
Ok src ->
|
||||
( { model | sources = Dict.insert pageName src model.sources }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
Err err ->
|
||||
( model, Cmd.none )
|
||||
|
||||
|
||||
|
||||
-- SUBSCRIPTIONS
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions _ =
|
||||
Sub.none
|
||||
|
||||
|
||||
|
||||
-- VIEW
|
||||
|
||||
|
||||
view : Model -> Browser.Document Msg
|
||||
view model =
|
||||
{ title = "gen2.space ~ " ++ nameFromRoute model.route
|
||||
, body =
|
||||
[ layout
|
||||
[ Font.family
|
||||
[ Font.typeface "Monoid"
|
||||
, Font.typeface "monospace"
|
||||
, Font.monospace
|
||||
]
|
||||
]
|
||||
(page model)
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
navbarHeader =
|
||||
link
|
||||
[ centerX
|
||||
, centerY
|
||||
, Font.size 30
|
||||
]
|
||||
{ url = "/", label = image [ width fill ] { src = "/data/banner.png", description = "gen2 space" } }
|
||||
|
||||
|
||||
navbarLinks =
|
||||
List.map
|
||||
(\pageLink ->
|
||||
link
|
||||
[ Font.color basedPurple ]
|
||||
{ url = "/" ++ pageLink
|
||||
, label = text ("/" ++ pageLink)
|
||||
}
|
||||
)
|
||||
[ ""
|
||||
, "posts"
|
||||
, "about"
|
||||
]
|
||||
|> row
|
||||
[ centerX
|
||||
, spacing 30
|
||||
]
|
||||
|
||||
|
||||
navbar =
|
||||
column
|
||||
[ width fill
|
||||
, greenLines
|
||||
, spacing 10
|
||||
, padding 10
|
||||
]
|
||||
[ navbarHeader, navbarLinks ]
|
||||
|
||||
|
||||
page model =
|
||||
column
|
||||
[ width fill
|
||||
, height fill
|
||||
, linesBackground "#222222"
|
||||
, spacing 20
|
||||
]
|
||||
[ navbar
|
||||
, body model
|
||||
]
|
||||
|
||||
|
||||
posts =
|
||||
Dict.fromList
|
||||
[ ( "viveahk", { subtext = "Using the Vive Pro controllers on Windows to run shortucts" } )
|
||||
, ( "librebasics", { subtext = "How to use the internet for free* in poor countries" } )
|
||||
]
|
||||
|
||||
|
||||
postPreview ( name, data ) =
|
||||
textColumn [ width fill, spacing 15 ] [ link [ Font.color basedPurple ] { url = "/posts/" ++ name, label = niceHeader ("Post: " ++ name) }, paragraph [] [ text data.subtext ] ]
|
||||
|
||||
|
||||
postsText =
|
||||
[ List.map postPreview (Dict.toList posts)
|
||||
|> textColumn [ width fill, spacing 50 ]
|
||||
]
|
||||
|
||||
|
||||
notFoundLines =
|
||||
[ text "this page doesn't exist, sorry" ]
|
||||
|
||||
|
||||
postText model name =
|
||||
case Dict.get name posts of
|
||||
Nothing ->
|
||||
notFoundLines
|
||||
|
||||
Just data ->
|
||||
niceBigHeader name :: [ ezmd (Maybe.withDefault "" (Dict.get ("posts/" ++ name) model.sources)) ]
|
||||
|
||||
|
||||
body model =
|
||||
el
|
||||
[ linesBackground "#220044"
|
||||
, Font.color (rgb255 255 255 255)
|
||||
, padding 30
|
||||
, width (maximum 1300 fill)
|
||||
, centerX
|
||||
]
|
||||
(textColumn [ width fill, spacing 15 ]
|
||||
(case model.route of
|
||||
Posts ->
|
||||
postsText
|
||||
|
||||
Post name ->
|
||||
postText model name
|
||||
|
||||
NotFound ->
|
||||
notFoundLines
|
||||
|
||||
_ ->
|
||||
[ ezmd (Maybe.withDefault "" (Dict.get (nameFromRoute model.route) model.sources)) ]
|
||||
)
|
||||
)
|
51
src/SiteComponents.elm
Normal file
51
src/SiteComponents.elm
Normal file
@ -0,0 +1,51 @@
|
||||
module SiteComponents exposing (basedGreen, basedPurple, edges, greenLines, linesBackground, niceBigHeader, niceHeader)
|
||||
|
||||
import Element exposing (..)
|
||||
import Element.Font as Font
|
||||
import Html.Attributes
|
||||
|
||||
|
||||
edges =
|
||||
{ top = 0
|
||||
, right = 0
|
||||
, bottom = 0
|
||||
, left = 0
|
||||
}
|
||||
|
||||
|
||||
basedPurple =
|
||||
rgb255 40 0 90
|
||||
|
||||
|
||||
basedGreen =
|
||||
rgb255 20 100 20
|
||||
|
||||
|
||||
linesBackground cssColor =
|
||||
htmlAttribute (Html.Attributes.style "background" ("repeating-linear-gradient(" ++ cssColor ++ ", " ++ cssColor ++ " 1px, #2F2F2F 1px, #2F2F2F 2px)"))
|
||||
|
||||
|
||||
greenLines =
|
||||
linesBackground "#004400"
|
||||
|
||||
|
||||
niceHeader headerText =
|
||||
el
|
||||
[ width fill
|
||||
, height shrink
|
||||
, padding 10
|
||||
, Font.size 24
|
||||
, greenLines
|
||||
]
|
||||
(text headerText)
|
||||
|
||||
|
||||
niceBigHeader headerText =
|
||||
el
|
||||
[ width fill
|
||||
, height shrink
|
||||
, padding 10
|
||||
, Font.size 30
|
||||
, greenLines
|
||||
]
|
||||
(text headerText)
|
7
src/index.js
Normal file
7
src/index.js
Normal file
@ -0,0 +1,7 @@
|
||||
const { Elm } = require('./Main.elm');
|
||||
|
||||
Elm.Main.init({});
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => navigator.serviceWorker.register('/sw.js'));
|
||||
}
|
BIN
versions.dat
Normal file
BIN
versions.dat
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user