gdk-toogle 0.7.0 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc23503c85ec958b0051f3dd65ae20430ef7260df40441c6bc887b5caa1b3502
4
- data.tar.gz: f88f8017af1429e311e216cab810197c4d4b5d9feafa327633dda26e84a70739
3
+ metadata.gz: b41975a3c2a35c12eecaad91aa7bfd949d68d0132576d1f68ecca48987abf641
4
+ data.tar.gz: ad9ede84ae8f37f9286699d33163f360a04854a00abb3fbfb4ec6b07e3ec386f
5
5
  SHA512:
6
- metadata.gz: b99d1e496643408bfaee5ff88409e5136fb89fa895b36b8f94ee08210a4d9ae03fe578d4699e5552672fceb345bb9d83c82ee557147348057d712b73e7803ce5
7
- data.tar.gz: d24eaa1a2864ab9734d242843f7fc5cda999946fe361fc13d3a023d7c312d9dded7fa78c51a02094a231c171a5e4f92bb972bb1474e254fe24e5c62cd3e70c27
6
+ metadata.gz: 20a49dff67060c27ab608f9851570494726856f34e0deb11ad3c60266b72a3af13260384c63ddf3afe3284449e9984e03f3fd345a9302c6e132760a515c124eb
7
+ data.tar.gz: 1d372ec1b321404ad287154a027aef0a1732116ffedd449602bcd57f57e4d4d77b0a0e5ea11f2e5ed5e7c5caf3901ae99569485f3db8c0e50c7bc5f581ba5957
@@ -1 +1,2 @@
1
1
  //= link toogle/application.css
2
+ //= link toogle/application.js
@@ -0,0 +1,117 @@
1
+ document.addEventListener("alpine:init", () => {
2
+ Alpine.data("features", (indexUrl) => ({
3
+ features: [],
4
+ indexUrl,
5
+
6
+ init() {
7
+ fetch(this.indexUrl, {
8
+ method: "GET",
9
+ headers: {
10
+ Accept: "application/json",
11
+ },
12
+ })
13
+ .then((response) => response.json())
14
+ .then((data) => {
15
+ this.features = data;
16
+ })
17
+ .catch((error) => console.error("Error fetching data:", error));
18
+ },
19
+
20
+ toggleFeature(feature) {
21
+ const newState = feature.state === "enabled" ? "disabled" : "enabled";
22
+ fetch(`${this.indexUrl}/${feature.name}`, {
23
+ method: "PUT",
24
+ headers: {
25
+ Accept: "application/json",
26
+ "Content-Type": "application/json",
27
+ },
28
+ body: JSON.stringify({
29
+ state: newState,
30
+ }),
31
+ }).then(() => {
32
+ this.features = this.features.map((f) => {
33
+ return f === feature ? { ...f, state: newState } : f;
34
+ });
35
+ });
36
+ },
37
+
38
+ deleteFeature(featureName) {
39
+ const csrfToken = document.head.querySelector(
40
+ "meta[name=csrf-token]"
41
+ )?.content;
42
+
43
+ fetch(`${this.indexUrl}/${featureName}`, {
44
+ method: "DELETE",
45
+ headers: {
46
+ Accept: "application/json",
47
+ "X-CSRF-Token": csrfToken,
48
+ },
49
+ }).then(() => {
50
+ this.features = this.features.filter((f) => f.name !== featureName);
51
+ });
52
+ },
53
+ }));
54
+
55
+ Alpine.data("toggle", (featureName, isChecked, indexUrl) => ({
56
+ name: featureName,
57
+ checked: isChecked,
58
+ indexUrl,
59
+
60
+ input: {
61
+ ["@change"]() {
62
+ const csrfToken = document.head.querySelector(
63
+ "meta[name=csrf-token]"
64
+ )?.content;
65
+
66
+ fetch(`${this.indexUrl}/${this.name}`, {
67
+ method: "PUT",
68
+ headers: {
69
+ "Content-Type": "application/json",
70
+ "X-CSRF-Token": csrfToken,
71
+ },
72
+ body: JSON.stringify({
73
+ state: this.checked ? "disabled" : "enabled",
74
+ }),
75
+ }).then(() => {
76
+ window.location = this.indexUrl;
77
+ });
78
+ },
79
+ },
80
+ }));
81
+
82
+ Alpine.data("darkModeSwitcher", () => ({
83
+ isDark: undefined,
84
+
85
+ init() {
86
+ const cookieValue = this.getCookieValue();
87
+ if (cookieValue) {
88
+ this.isDark = cookieValue === "true";
89
+ } else {
90
+ this.isDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
91
+ }
92
+ },
93
+
94
+ getCookieValue() {
95
+ return (
96
+ document.cookie
97
+ .match("(^|;)\\s*" + "toogle-dark" + "\\s*=\\s*([^;]+)")
98
+ ?.pop() || ""
99
+ );
100
+ },
101
+
102
+ button: {
103
+ ["@click"]() {
104
+ this.isDark = !this.isDark;
105
+ document.cookie = `toogle-dark=${this.isDark}; SameSite=Strict`;
106
+ if (this.isDark) {
107
+ document.documentElement.classList.remove("light-mode");
108
+ } else {
109
+ document.documentElement.classList.add("light-mode");
110
+ }
111
+ },
112
+ ["x-bind:title"]() {
113
+ return `Switch to ${this.isDark ? "Light Mode" : "Dark Mode"}`;
114
+ },
115
+ },
116
+ }));
117
+ });
@@ -8,8 +8,6 @@
8
8
  @import "components/scrollbox";
9
9
  @import "components/toggle";
10
10
 
11
- @import "dark-mode";
12
-
13
11
  [x-cloak] {
14
12
  display: none !important;
15
13
  }
@@ -1,6 +1,10 @@
1
1
  .card {
2
- background-color: #f0f0f0;
2
+ background-color: hsl(
3
+ var(--hue-primary),
4
+ var(--saturation-bg),
5
+ var(--lightness-bg1)
6
+ );
3
7
  border-radius: 5px;
4
8
  padding: 2rem;
5
- box-shadow: 0 0.5rem 1rem #888;
9
+ box-shadow: 0 10px 16px var(--color-shadow);
6
10
  }
@@ -1,13 +1,26 @@
1
1
  .scrollbox {
2
2
  max-height: 20ch;
3
3
  overflow: auto;
4
- padding: 1em 0;
4
+ padding: 1rem 0;
5
5
  word-break: break-all;
6
6
 
7
- background-color: white;
8
- border: 2px solid #444;
7
+ background-color: hsl(
8
+ var(--hue-primary),
9
+ var(--saturation-bg),
10
+ var(--lightness-bg2)
11
+ );
12
+ border: 2px solid
13
+ hsl(var(--hue-primary), var(--saturation-bg), var(--lightness-bg1));
9
14
 
10
- li:hover {
11
- background-color: rgba(153, 153, 153, 0.1);
15
+ border-style: ridge;
16
+
17
+ box-shadow: 0 5px 10px var(--color-shadow);
18
+
19
+ li {
20
+ padding: 0 1rem;
21
+
22
+ &:hover {
23
+ background-color: hsl(var(--hue-primary), 60%, var(--lightness-bg1));
24
+ }
12
25
  }
13
26
  }
@@ -1,8 +1,11 @@
1
1
  html {
2
- --page-bg: #ddd;
3
-
4
- background-color: var(--page-bg);
2
+ color: var(--color-text);
5
3
  transition: 0.2s;
4
+ background-image: radial-gradient(
5
+ circle at 10vh 10vw,
6
+ hsl(var(--hue-primary), var(--saturation-bg), var(--lightness-bg1)),
7
+ hsl(var(--hue-primary), var(--saturation-bg), var(--lightness-bg0))
8
+ );
6
9
  }
7
10
 
8
11
  body {
@@ -11,7 +14,6 @@ body {
11
14
  > header {
12
15
  position: sticky;
13
16
  top: 0;
14
- background-color: var(--page-bg);
15
17
  transition: 0.2s;
16
18
  }
17
19
  }
@@ -27,34 +29,58 @@ p {
27
29
  }
28
30
 
29
31
  a {
30
- color: #222;
32
+ color: var(--color-primary);
31
33
  font-weight: bold;
32
34
  text-decoration: none;
33
- padding: 2px;
34
35
  border-radius: 2px;
35
36
  transition: outline 0.2s;
36
37
 
37
38
  &:focus {
38
- outline: 4px solid var(--color-primary);
39
+ outline: 2px solid var(--color-primary);
39
40
  }
40
41
  }
41
42
 
43
+ footer a {
44
+ color: var(--color-text);
45
+ }
46
+
42
47
  input[type="submit"]:not(.small) {
43
48
  font-size: large;
44
49
  padding: 0.25rem;
45
50
  }
46
51
 
47
- input[type="search"] {
52
+ input[type="search"],
53
+ input[type="text"] {
48
54
  margin: 0.25rem 0;
49
55
  padding: 0.75rem;
50
56
  font-family: monospace;
51
57
  border-radius: 0.5rem;
52
58
 
59
+ &:not(:read-only):focus {
60
+ outline: 2px solid var(--color-primary);
61
+ }
62
+
63
+ &:read-only:focus {
64
+ outline: none;
65
+ }
66
+
53
67
  &.large {
54
68
  font-size: large;
55
69
  }
56
70
  }
57
71
 
72
+ input[type="search"],
73
+ input[type="text"] {
74
+ color: hsl(var(--hue-primary), var(--saturation-bg), var(--lightness-fg));
75
+ background-color: hsl(
76
+ var(--hue-primary),
77
+ var(--saturation-bg),
78
+ var(--lightness-bg2)
79
+ );
80
+ border: none;
81
+ box-shadow: inset 1px 1px 2px var(--color-shadow);
82
+ }
83
+
58
84
  hr {
59
85
  margin: 1.5rem 0;
60
86
  }
@@ -64,6 +90,7 @@ code {
64
90
  }
65
91
 
66
92
  button {
93
+ color: var(--color-text);
67
94
  cursor: pointer;
68
95
  background-color: transparent;
69
96
  border: none;
@@ -84,13 +111,9 @@ button {
84
111
  }
85
112
 
86
113
  &:focus {
87
- outline: 4px solid var(--color-primary);
114
+ outline: 2px solid var(--color-primary);
88
115
  opacity: 1 !important;
89
116
  }
90
-
91
- > svg + span {
92
- margin-left: 0.25em;
93
- }
94
117
  }
95
118
 
96
119
  ul {
@@ -108,6 +131,7 @@ ul {
108
131
 
109
132
  dialog {
110
133
  background-color: transparent;
134
+ color: var(--color-text);
111
135
  border: none;
112
136
  outline: none;
113
137
 
@@ -26,6 +26,8 @@ body {
26
26
  > main {
27
27
  display: flex;
28
28
  flex-direction: column-reverse;
29
+ align-items: stretch;
30
+ justify-content: start;
29
31
  width: 100ch;
30
32
  max-width: 95%;
31
33
  margin: auto;
@@ -64,6 +66,16 @@ li.feature-toggle {
64
66
  padding: 0.5rem;
65
67
  }
66
68
 
69
+ .more-info {
70
+ padding-left: 68px; /* toggle width */
71
+ }
72
+
73
+ .metadata {
74
+ display: grid;
75
+ grid-template-columns: auto 1fr;
76
+ gap: 0.5rem;
77
+ }
78
+
67
79
  &:hover {
68
80
  background-color: rgba(153, 153, 153, 0.1);
69
81
 
@@ -1,3 +1,23 @@
1
- :root {
2
- --color-primary: #fca326;
1
+ html {
2
+ --hue-primary: 35;
3
+ --saturation-bg: 5%;
4
+ --lightness-bg0: 80%;
5
+ --lightness-bg1: 88%;
6
+ --lightness-bg2: 96%;
7
+ --lightness-fg: 10%;
8
+ --lightness-shadow: 50%;
9
+
10
+ --color-primary: hsl(var(--hue-primary), 90%, 50%);
11
+ --color-text: hsl(var(--hue-primary), 0%, var(--lightness-fg));
12
+ --color-shadow: hsl(0, var(--saturation-bg), var(--lightness-shadow));
13
+ }
14
+
15
+ @media (prefers-color-scheme: dark) {
16
+ html:not(.light-mode) {
17
+ --lightness-bg0: 8%;
18
+ --lightness-bg1: 16%;
19
+ --lightness-bg2: 24%;
20
+ --lightness-fg: 90%;
21
+ --lightness-shadow: 4%;
22
+ }
3
23
  }
@@ -2,6 +2,11 @@ module Toogle
2
2
  class FeaturesController < ApplicationController
3
3
  def index
4
4
  @features = Toogle::Feature.all
5
+
6
+ respond_to do |format|
7
+ format.html
8
+ format.json { render json: @features }
9
+ end
5
10
  end
6
11
 
7
12
  def show
@@ -35,7 +40,16 @@ module Toogle
35
40
 
36
41
  def destroy
37
42
  ::Feature.remove(params[:id])
38
- redirect_to features_url, status: :see_other
43
+
44
+ respond_to do |format|
45
+ format.html do
46
+ redirect_to features_url, status: :see_other
47
+ end
48
+
49
+ format.json do
50
+ head :ok
51
+ end
52
+ end
39
53
  end
40
54
  end
41
55
  end
@@ -6,7 +6,13 @@ module Toogle
6
6
 
7
7
  def self.all
8
8
  ::Feature::Definition.definitions.map do |definition|
9
- new(name: definition[0].to_s, default_enabled: definition[1].default_enabled)
9
+ new(
10
+ name: definition[0].to_s,
11
+ default_enabled: definition[1].default_enabled,
12
+ milestone: definition[1].milestone,
13
+ introduced_by_url: definition[1].introduced_by_url,
14
+ rollout_issue_url: definition[1].rollout_issue_url,
15
+ )
10
16
  end
11
17
  end
12
18
 
@@ -19,9 +25,12 @@ module Toogle
19
25
  all.find { |definition| definition.name == name }
20
26
  end
21
27
 
22
- def initialize(name:, default_enabled:)
28
+ def initialize(name:, default_enabled:, milestone: nil, introduced_by_url: nil, rollout_issue_url: nil)
23
29
  @name = name
24
30
  @default_enabled = default_enabled
31
+ @milestone = milestone
32
+ @introduced_by_url = introduced_by_url
33
+ @rollout_issue_url = rollout_issue_url
25
34
  end
26
35
  end
27
36
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Toogle
4
4
  class Feature
5
- attr_accessor :name, :state
5
+ attr_accessor :name, :state, :definition
6
6
 
7
7
  def self.all
8
8
  definitions = Definition.all
@@ -11,21 +11,22 @@ module Toogle
11
11
  feature_class: ::Feature::FlipperFeature,
12
12
  gate_class: ::Feature::FlipperGate
13
13
  ).get_all.map do |feature_name, feature_values|
14
- feature_exists_on_current_branch = definitions.any?{ |d| d.name == feature_name }
15
- feature_state = if feature_exists_on_current_branch
14
+ feature_definition = Definition.find(feature_name)
15
+ feature_state = if feature_definition
16
16
  feature_values[:boolean] ? :enabled: :disabled
17
17
  else
18
18
  # This usually happens when switching back from an unmerged feature
19
19
  # branch that introduces a new flag, or when a flag got deleted.
20
20
  :unknown
21
21
  end
22
- new(name: feature_name, state: feature_state)
22
+ new(name: feature_name, state: feature_state, definition: feature_definition)
23
23
  end
24
24
  end
25
25
 
26
- def initialize(name:, state:)
26
+ def initialize(name:, state:, definition:)
27
27
  @name = name
28
28
  @state = state
29
+ @definition = definition
29
30
  end
30
31
  end
31
32
  end
@@ -7,8 +7,10 @@
7
7
  = csrf_meta_tags
8
8
  = csp_meta_tag
9
9
  = stylesheet_link_tag "toogle/application", media: "all"
10
+ = javascript_include_tag 'toogle/application'
10
11
  %script(defer src="https://cdn.jsdelivr.net/npm/@alpinejs/anchor@3.x.x/dist/cdn.min.js")
11
12
  %script(defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js")
13
+
12
14
  %body
13
15
  %header
14
16
  %nav.d-flex.gap
@@ -38,6 +40,7 @@
38
40
  %path(d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z")
39
41
 
40
42
  %main
43
+ = yield
41
44
  - if notice.present?
42
45
  #notice.d-flex.row.center.gap
43
46
  %svg(width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round")
@@ -45,9 +48,7 @@
45
48
  %line(x1="12" y1="16" x2="12" y2="12")
46
49
  %line(x1="12" y1="8" x2="12.01" y2="8")
47
50
  %span.grow= notice
48
- = yield
51
+
49
52
  %footer
50
53
  %a(href="https://gitlab.com/thutterer/toogle" target="_blank")
51
54
  = Toogle::VERSION
52
-
53
- = render "alpine_components"
@@ -3,7 +3,7 @@
3
3
  - name = definition.name
4
4
  - enabled = definition.default_enabled
5
5
  %li.d-flex.center.row.nowrap(x-show="$el.textContent.includes(query) || query == ''")
6
- %label.toggle(x-data="toggle('#{name}', #{enabled})")
6
+ %label.toggle(x-data="toggle('#{name}', #{enabled}, '#{features_url}')")
7
7
  %input(type="checkbox" x-bind="input" x-model="checked"){checked: enabled}
8
8
  %span.handle.round(:title="checked ? 'Enabled by default. Click to disable.' : 'Disabled by default. Click to enable.'")
9
9
  %code.grow= name
@@ -2,7 +2,7 @@
2
2
  .card{"x-on:click.outside": "$refs.dialog.close()"}
3
3
  %header
4
4
  %h2
5
- %label.toggle(x-data="toggle(feature, isAlreadyEnabled)")
5
+ %label.toggle(x-data="toggle(feature, isAlreadyEnabled, '#{features_url}')")
6
6
  %input(type="checkbox" x-bind="input" x-model="checked")
7
7
  %span.handle.round
8
8
 
@@ -1,46 +1,71 @@
1
- .grow
2
- .card
3
- %h3 My feature flags
4
- %small These features already use custom settings in this GDK.
5
-
6
- - if @features.any?
7
- %ul
8
- - @features.each do |feature|
9
- %li.feature-toggle(x-data="{ showMore: false }")
10
- .d-flex.row
11
- = render "toggle", feature: feature
12
-
13
- %code.grow= feature.name
14
-
15
- %button(title="Show Share URL" x-on:click="showMore = !showMore")
16
- %svg(xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round")
17
- %path(d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8")
18
- %polyline(points="16 6 12 2 8 6")
19
- %line(x1="12" y1="2" x2="12" y2="15")
20
-
21
- = render "remove", feature: feature
22
-
23
- .d-flex.col(x-show="showMore" x-data="{text: '#{request.url}#{feature.name}'}"){'@click.outside' => 'showMore = false'}
24
- %small Share this URL with MR reviewers.
25
- .d-flex.row
26
- %input.grow(x-ref="copyText" x-model="text" type="text" readonly="readonly")
27
- %button(x-on:click="$refs.copyText.select(); document.execCommand('copy');") Copy
28
- - else
29
- %p No active feature flags in this GDK yet.
30
-
31
- .grow.d-flex
32
- .card.grow(style="align-self: center;")
33
- %h3 Search and toggle feature flags
34
- .d-flex.col{
35
- "x-data": "{query: '', show: false}",
36
- "@click.outside": 'show = false'}
37
- %input.large.w-100#search{
38
- "type": "search",
39
- "x-model.debounce.400ms": "query",
40
- "x-ref": "search",
41
- "x-on:focus": "show = true"}
1
+ .card
2
+ %h3 My feature flags
3
+ %small These features already use custom settings in this GDK.
4
+
5
+ %ul(x-data="features('#{features_url}')")
6
+ %template(x-for="feature in features" :key="feature.name")
7
+ %li.feature-toggle(x-data="{ showMore: false }"){"@click.outside": "showMore = false"}
8
+ .d-flex.row
9
+ %template(x-if="feature.state === 'unknown'")
10
+ %label.toggle(title="This feature does not exist on the current branch.")
11
+ %input(type="checkbox" disabled :name="feature.name")
12
+ %span.handle.round
13
+ %template(x-if="feature.state !== 'unknown'")
14
+ %label.toggle
15
+ %input(type="checkbox" x-on:change="toggleFeature(feature)" :checked="feature.state === 'enabled'" :name="feature.name")
16
+ %span.handle.round
17
+
18
+ %code.grow(x-text="feature.name")
19
+
20
+ %button(title="Show more" x-on:click="showMore = !showMore")
21
+ %svg(xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round")
22
+ %circle(cx="12" cy="12" r="1")
23
+ %circle(cx="12" cy="5" r="1")
24
+ %circle(cx="12" cy="19" r="1")
25
+
26
+ %button(title="Forget this setting and use default" x-on:click="deleteFeature(feature.name)")
27
+ %svg(xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round")
28
+ %line(x1="18" y1="6" x2="6" y2="18")
29
+ %line(x1="6" y1="6" x2="18" y2="18")
30
+
31
+ .d-flex.col.more-info{ "x-show": "showMore" }
32
+ .metadata
33
+ %strong Milestone
34
+ %span(x-text="feature.definition.milestone || '-'")
35
+ %strong Introduced by
36
+ %a(x-show="feature.definition.introduced_by_url"
37
+ x-text="`!${feature.definition.introduced_by_url?.split('/').at(-1)}`"
38
+ :href="feature.definition.introduced_by_url"
39
+ target="_blank")
40
+ %span(x-show="!feature.definition.introduced_by_url") -
41
+ %strong Rollout issue
42
+ %a(x-show="feature.definition.rollout_issue_url"
43
+ x-text="`#${feature.definition.rollout_issue_url?.split('/').at(-1)}`"
44
+ :href="feature.definition.rollout_issue_url"
45
+ target="_blank")
46
+ %span(x-show="!feature.definition.rollout_issue_url") -
47
+
48
+ %hr
49
+ %small Share this URL with MR reviewers.
50
+ .d-flex.row
51
+ %input.grow(x-ref="copyText" :value="`${indexUrl}${feature.name}`" type="text" readonly="readonly")
52
+ %button(x-on:click="$refs.copyText.select(); document.execCommand('copy');") Copy
53
+ %p(x-show="!features.length") No active feature flags in this GDK yet.
54
+
55
+ .card(style="margin: 8vh 0 5vh;")
56
+ %h3 Search and toggle feature flags
57
+ .d-flex.col{
58
+ "x-data": "{query: '', show: false}",
59
+ "@click.outside": "show = false",
60
+ "@keyup.esc": "show = false"}
61
+ %input.large.w-100#search{
62
+ "type": "search",
63
+ "x-model.debounce.400ms": "query",
64
+ "x-ref": "search",
65
+ "x-on:input": "show = true",
66
+ "x-on:focus": "show = true"}
67
+ %template(x-if="show")
42
68
  .d-flex.col.stretch{
43
- "x-show": "show",
44
69
  "x-anchor.bottom-start.offset.5" => "$refs.search",
45
70
  "x-transition": nil}
46
71
  .grow{
@@ -1,3 +1,3 @@
1
1
  module Toogle
2
- VERSION = "0.7.0"
2
+ VERSION = "0.9.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gdk-toogle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Hutterer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-13 00:00:00.000000000 Z
11
+ date: 2024-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -92,11 +92,11 @@ files:
92
92
  - README.md
93
93
  - Rakefile
94
94
  - app/assets/config/toogle_manifest.js
95
+ - app/assets/javascript/toogle/application.js
95
96
  - app/assets/stylesheets/toogle/application.css
96
97
  - app/assets/stylesheets/toogle/components/card.css
97
98
  - app/assets/stylesheets/toogle/components/scrollbox.css
98
99
  - app/assets/stylesheets/toogle/components/toggle.css
99
- - app/assets/stylesheets/toogle/dark-mode.css
100
100
  - app/assets/stylesheets/toogle/elements.css
101
101
  - app/assets/stylesheets/toogle/layout.css
102
102
  - app/assets/stylesheets/toogle/utilities.css
@@ -107,10 +107,8 @@ files:
107
107
  - app/models/toogle/definition.rb
108
108
  - app/models/toogle/feature.rb
109
109
  - app/views/layouts/toogle/application.html.haml
110
- - app/views/toogle/application/_alpine_components.html.haml
111
110
  - app/views/toogle/definitions/index.html.haml
112
111
  - app/views/toogle/features/_dialog.html.haml
113
- - app/views/toogle/features/_remove.html.haml
114
112
  - app/views/toogle/features/_toggle.html.haml
115
113
  - app/views/toogle/features/index.html.haml
116
114
  - config/routes.rb
@@ -1,25 +0,0 @@
1
- @media (prefers-color-scheme: dark) {
2
- html:not(.light-mode) {
3
- --page-bg: #181822;
4
-
5
- color: #eee;
6
-
7
- a {
8
- color: #ddd;
9
- }
10
-
11
- button,
12
- dialog {
13
- color: #eee;
14
- }
15
-
16
- .card {
17
- background-color: #282833;
18
- box-shadow: 0 0.5rem 1rem #111;
19
- }
20
-
21
- .scrollbox {
22
- background-color: #444;
23
- }
24
- }
25
- }
@@ -1,56 +0,0 @@
1
- :javascript
2
- document.addEventListener("alpine:init", () => {
3
- Alpine.data("toggle", (featureName, isChecked) => ({
4
- name: featureName,
5
- checked: isChecked,
6
-
7
- input: {
8
- ['@change']() {
9
- fetch(`./${this.name}.json`, {
10
- method: "PUT",
11
- headers: {
12
- 'Content-Type': 'application/json'
13
- },
14
- body: JSON.stringify({state: this.checked ? 'disabled' : 'enabled'})
15
- }).then(() => {
16
- // Always reload the page after change as a lazy way to move newly
17
- // enabled feature flags into the top section.
18
- // TODO: Either make this a classic form element or go full Alpine.
19
- window.location = '#{features_url}'
20
- })
21
- },
22
- },
23
- }));
24
-
25
- Alpine.data("darkModeSwitcher", () => ({
26
- isDark: undefined,
27
-
28
- init() {
29
- const cookieValue = this.getCookieValue()
30
- if (cookieValue) {
31
- this.isDark = cookieValue === "true"
32
- } else {
33
- this.isDark = window.matchMedia("(prefers-color-scheme: dark)").matches
34
- }
35
- },
36
-
37
- getCookieValue() {
38
- return document.cookie.match('(^|;)\\s*' + 'toogle-dark' + '\\s*=\\s*([^;]+)')?.pop() || ''
39
- },
40
-
41
- button: {
42
- ['@click']() {
43
- this.isDark = !this.isDark
44
- document.cookie = `toogle-dark=${this.isDark}; SameSite=Strict`
45
- if(this.isDark) {
46
- document.documentElement.classList.remove('light-mode');
47
- } else {
48
- document.documentElement.classList.add('light-mode');
49
- }
50
- },
51
- ['x-bind:title']() {
52
- return `Switch to ${this.isDark ? 'Light Mode' : 'Dark Mode'}`
53
- }
54
- },
55
- }));
56
- });
@@ -1,4 +0,0 @@
1
- = button_to feature_path(feature.name), method: :delete, title: "Forget this setting and use default" do
2
- %svg(xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round")
3
- %line(x1="18" y1="6" x2="6" y2="18")
4
- %line(x1="6" y1="6" x2="18" y2="18")