picocrank 1.13.0 → 1.13.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "picocrank",
3
- "version": "1.13.0",
3
+ "version": "1.13.2",
4
4
  "description": "A set of zero dependency Vue components built on the Femtocrank global CSS theme.",
5
5
  "main": "vite.config.js",
6
6
  "scripts": {
@@ -1,8 +1,12 @@
1
1
  <template>
2
2
  <header>
3
- <div class = "image-and-title flex-row" :id = "sidebarEnabled ? 'sidebar-button' : null" @click = "sidebarEnabled && emit('toggleSidebar')">
4
- <img :src = "logoUrl" alt = "Logo" class = "logo" />
5
- <h1>{{ title }}</h1>
3
+ <div
4
+ :id = "sidebarEnabled ? 'sidebar-button' : null"
5
+ :class="['image-and-title', 'flex-row', { 'disabled-branding': !showBranding }]"
6
+ @click = "sidebarEnabled && emit('toggleSidebar')"
7
+ >
8
+ <img v-if="showBranding" :src = "logoUrl" alt = "Logo" class = "logo" />
9
+ <h1 v-if="showBranding">{{ title }}</h1>
6
10
 
7
11
  <div class = "fg1" />
8
12
 
@@ -57,6 +61,10 @@
57
61
  type: Boolean,
58
62
  default: true,
59
63
  },
64
+ showBranding: {
65
+ type: Boolean,
66
+ default: true,
67
+ },
60
68
  topBarEnabled: {
61
69
  type: Boolean,
62
70
  default: false,
@@ -78,6 +86,10 @@ button:hover {
78
86
  background-color: transparent;
79
87
  }
80
88
 
89
+ #sidebar-button.disabled-branding {
90
+ width: auto;
91
+ }
92
+
81
93
  .user-info span {
82
94
  padding-right: 0.5rem;
83
95
  }
@@ -107,6 +107,10 @@ function getNavigationLinks() {
107
107
  }
108
108
 
109
109
  function isActive(link) {
110
+ if (!route || !link) {
111
+ return false
112
+ }
113
+
110
114
  // If link has a 'to' object with a name, compare route name and params
111
115
  if (link.to && typeof link.to === 'object' && link.to.name) {
112
116
  // Compare route names first
package/vue/views/App.vue CHANGED
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <Header username = "Guest" @toggleSidebar="toggleSidebar" title = "PicoCrank" :logoUrl="logoUrl" :sidebarEnabled="sidebarEnabled" :navigation="navigation" :topBarEnabled="topBarEnabled">
2
+ <Header username = "Guest" @toggleSidebar="toggleSidebar" title = "PicoCrank" :logoUrl="logoUrl" :sidebarEnabled="sidebarEnabled" :navigation="navigation" :topBarEnabled="topBarEnabled" :showBranding="brandingEnabled">
3
3
  <template #toolbar>
4
4
  <QuickSearch
5
5
  v-if="quickSearchEnabled"
@@ -43,6 +43,7 @@
43
43
  const sidebar = ref(null);
44
44
  const navigation = ref(null);
45
45
  const sidebarEnabled = ref(true);
46
+ const brandingEnabled = ref(true);
46
47
  const quickSearchEnabled = ref(true);
47
48
  const topBarEnabled = ref(false);
48
49
 
@@ -56,6 +57,10 @@
56
57
  sidebarEnabled.value = !sidebarEnabled.value;
57
58
  }
58
59
 
60
+ function toggleBrandingEnabled() {
61
+ brandingEnabled.value = !brandingEnabled.value;
62
+ }
63
+
59
64
  function toggleQuickSearchEnabled() {
60
65
  quickSearchEnabled.value = !quickSearchEnabled.value;
61
66
  }
@@ -67,6 +72,9 @@
67
72
  // Provide sidebar, QuickSearch, and TopBar state and toggle functions for child components
68
73
  provide('sidebarEnabled', sidebarEnabled);
69
74
  provide('toggleSidebarEnabled', toggleSidebarEnabled);
75
+ provide('brandingEnabled', brandingEnabled);
76
+ provide('toggleBrandingEnabled', toggleBrandingEnabled);
77
+
70
78
  provide('quickSearchEnabled', quickSearchEnabled);
71
79
  provide('toggleQuickSearchEnabled', toggleQuickSearchEnabled);
72
80
  provide('topBarEnabled', topBarEnabled);
@@ -1,102 +1,186 @@
1
1
  <template>
2
2
  <Section
3
3
  title="Form Example"
4
- subtitle="A simple form with various input types"
5
- >
4
+ subtitle="A simple form demonstrating Femtocrank form layout"
5
+ >
6
6
  <template #toolbar>
7
7
  <button @click="resetForm">Reset</button>
8
8
  </template>
9
9
 
10
10
  <form @submit.prevent="handleSubmit">
11
- <div class="form-group">
12
- <label for="name">Name</label>
13
- <input
14
- id="name"
15
- v-model="formData.name"
16
- type="text"
17
- placeholder="Enter your name"
18
- required
19
- />
20
- </div>
21
-
22
- <div class="form-group">
23
- <label for="email">Email</label>
24
- <input
25
- id="email"
26
- v-model="formData.email"
27
- type="email"
28
- placeholder="Enter your email"
29
- required
30
- />
31
- </div>
32
-
33
- <div class="form-group">
34
- <label for="country">Country</label>
35
- <select id="country" v-model="formData.country" required>
36
- <option value="">Select a country</option>
37
- <option value="us">United States</option>
38
- <option value="uk">United Kingdom</option>
39
- <option value="ca">Canada</option>
40
- <option value="au">Australia</option>
41
- <option value="de">Germany</option>
42
- <option value="fr">France</option>
43
- </select>
44
- </div>
45
-
46
- <div class="form-group">
47
- <label for="message">Message</label>
48
- <textarea
49
- id="message"
50
- v-model="formData.message"
51
- placeholder="Enter your message"
52
- rows="4"
53
- ></textarea>
11
+ <!-- Name -->
12
+ <label for="name">Name</label>
13
+ <input
14
+ id="name"
15
+ v-model="formData.name"
16
+ type="text"
17
+ placeholder="Enter your name"
18
+ required
19
+ />
20
+
21
+ <!-- Role (radio group) -->
22
+ <span class="fake-label">Role</span>
23
+ <div class="radio-group">
24
+ <label>
25
+ <input
26
+ type="radio"
27
+ name="role"
28
+ value="sales"
29
+ v-model="formData.role"
30
+ />
31
+ <span>Sales</span>
32
+ </label>
33
+ <label>
34
+ <input
35
+ type="radio"
36
+ name="role"
37
+ value="engineering"
38
+ v-model="formData.role"
39
+ />
40
+ <span>Engineering</span>
41
+ </label>
42
+ <label>
43
+ <input
44
+ type="radio"
45
+ name="role"
46
+ value="hr"
47
+ v-model="formData.role"
48
+ />
49
+ <span>HR</span>
50
+ </label>
54
51
  </div>
55
52
 
56
- <div class="form-group">
53
+ <!-- Salary (select) -->
54
+ <label for="salary">Salary</label>
55
+ <select id="salary" v-model="formData.salary">
56
+ <option value="0">Select a salary</option>
57
+ <option value="10000">£10,000</option>
58
+ <option value="20000">£20,000</option>
59
+ <option value="30000">£30,000</option>
60
+ <option value="40000">£40,000</option>
61
+ <option value="50000">£50,000</option>
62
+ </select>
63
+
64
+ <!-- Email -->
65
+ <label for="email">Email</label>
66
+ <input
67
+ id="email"
68
+ v-model="formData.email"
69
+ type="email"
70
+ placeholder="Enter your email"
71
+ required
72
+ />
73
+
74
+ <!-- Administrator checkbox -->
75
+ <label>Is Administrator?</label>
76
+ <input
77
+ type="checkbox"
78
+ id="is-admin"
79
+ v-model="formData.isAdmin"
80
+ />
81
+
82
+ <!-- Website -->
83
+ <label for="website">Website</label>
84
+ <input
85
+ id="website"
86
+ v-model="formData.website"
87
+ type="url"
88
+ placeholder="https://example.com"
89
+ />
90
+
91
+ <!-- Favourite food (disabled) -->
92
+ <label for="favourite-food">Favourite Food</label>
93
+ <input
94
+ id="favourite-food"
95
+ v-model="formData.favouriteFood"
96
+ type="text"
97
+ placeholder="e.g. Pizza"
98
+ disabled
99
+ />
100
+
101
+ <!-- Favourite colour -->
102
+ <label for="favourite-colour">Favourite Colour</label>
103
+ <input
104
+ id="favourite-colour"
105
+ v-model="formData.favouriteColour"
106
+ type="color"
107
+ />
108
+
109
+ <!-- Favourite number -->
110
+ <label for="favourite-number">Favourite Number</label>
111
+ <input
112
+ id="favourite-number"
113
+ v-model.number="formData.favouriteNumber"
114
+ type="number"
115
+ min="0"
116
+ max="100"
117
+ step="1"
118
+ />
119
+
120
+ <!-- Newsletters (checkbox group) -->
121
+ <span class="fake-label">
122
+ Newsletters
123
+ </span>
124
+ <div>
57
125
  <label>
58
126
  <input
59
- type="checkbox"
60
- v-model="formData.newsletter"
127
+ type="checkbox"
128
+ id="newsletter1"
129
+ v-model="formData.newsletter1"
61
130
  />
62
- Subscribe to newsletter
131
+ <span>Newsletter 1</span>
63
132
  </label>
64
- </div>
65
133
 
66
- <div class="form-group">
67
- <label>Preferred Contact Method</label>
68
- <div class="radio-group">
69
- <label>
70
- <input
71
- type="radio"
72
- v-model="formData.contactMethod"
73
- value="email"
74
- />
75
- Email
76
- </label>
77
- <label>
78
- <input
79
- type="radio"
80
- v-model="formData.contactMethod"
81
- value="phone"
82
- />
83
- Phone
84
- </label>
85
- <label>
86
- <input
87
- type="radio"
88
- v-model="formData.contactMethod"
89
- value="mail"
90
- />
91
- Mail
92
- </label>
93
- </div>
134
+ <label>
135
+ <input
136
+ type="checkbox"
137
+ id="newsletter2"
138
+ v-model="formData.newsletter2"
139
+ />
140
+ <span>Newsletter 2</span>
141
+ </label>
94
142
  </div>
95
143
 
96
- <div class="form-actions">
144
+ <!-- Comments -->
145
+ <label for="comments">Comments</label>
146
+ <textarea
147
+ id="comments"
148
+ v-model="formData.comments"
149
+ ></textarea>
150
+
151
+ <!-- Readonly textarea -->
152
+ <label for="readonly">Readonly</label>
153
+ <textarea
154
+ id="readonly"
155
+ v-model="formData.readonlyText"
156
+ readonly
157
+ ></textarea>
158
+
159
+ <!-- Disabled textarea -->
160
+ <label for="disabled">Disabled</label>
161
+ <textarea
162
+ id="disabled"
163
+ v-model="formData.disabledText"
164
+ disabled
165
+ ></textarea>
166
+
167
+ <!-- Datetime -->
168
+ <label for="datetime">
169
+ Datetime
170
+ </label>
171
+ <input
172
+ id="datetime"
173
+ type="datetime-local"
174
+ v-model="formData.datetime"
175
+ />
176
+
177
+ <!-- Buttons in fieldset to match simple.html -->
178
+ <fieldset>
97
179
  <button type="submit">Submit</button>
98
- <button type="button" @click="resetForm">Clear</button>
99
- </div>
180
+ <button type="button" @click="handleCancel">Cancel</button>
181
+ <button type="reset" @click="resetForm">Reset</button>
182
+ <button type="submit" disabled>Disabled</button>
183
+ </fieldset>
100
184
  </form>
101
185
 
102
186
  <div v-if="submitted" class="form-result">
@@ -112,11 +196,20 @@ import Section from '../components/Section.vue'
112
196
 
113
197
  const formData = ref({
114
198
  name: '',
199
+ role: '',
200
+ salary: '0',
115
201
  email: '',
116
- country: '',
117
- message: '',
118
- newsletter: false,
119
- contactMethod: 'email'
202
+ isAdmin: false,
203
+ website: '',
204
+ favouriteFood: '',
205
+ favouriteColour: '#dee3e7',
206
+ favouriteNumber: 50,
207
+ newsletter1: false,
208
+ newsletter2: false,
209
+ comments: '',
210
+ readonlyText: 'This is a readonly textarea.',
211
+ disabledText: 'This is a disabled textarea.',
212
+ datetime: ''
120
213
  })
121
214
 
122
215
  const submitted = ref(false)
@@ -128,141 +221,29 @@ function handleSubmit() {
128
221
  alert('Form submitted! Check the console and the form result below.')
129
222
  }
130
223
 
224
+ function handleCancel() {
225
+ // For demo purposes, just reset submitted state
226
+ submitted.value = false
227
+ }
228
+
131
229
  function resetForm() {
132
230
  formData.value = {
133
231
  name: '',
232
+ role: '',
233
+ salary: '0',
134
234
  email: '',
135
- country: '',
136
- message: '',
137
- newsletter: false,
138
- contactMethod: 'email'
235
+ isAdmin: false,
236
+ website: '',
237
+ favouriteFood: '',
238
+ favouriteColour: '#dee3e7',
239
+ favouriteNumber: 50,
240
+ newsletter1: false,
241
+ newsletter2: false,
242
+ comments: '',
243
+ readonlyText: 'This is a readonly textarea.',
244
+ disabledText: 'This is a disabled textarea.',
245
+ datetime: ''
139
246
  }
140
247
  submitted.value = false
141
248
  }
142
- </script>
143
-
144
- <style scoped>
145
- .form-group {
146
- margin-bottom: 1.5rem;
147
- }
148
-
149
- .form-group label {
150
- display: block;
151
- margin-bottom: 0.5rem;
152
- font-weight: 500;
153
- }
154
-
155
- .form-group input[type="text"],
156
- .form-group input[type="email"],
157
- .form-group select,
158
- .form-group textarea {
159
- width: 100%;
160
- padding: 0.5rem;
161
- border: 1px solid #ccc;
162
- border-radius: 0.25rem;
163
- font-size: 1rem;
164
- }
165
-
166
- .form-group textarea {
167
- resize: vertical;
168
- font-family: inherit;
169
- }
170
-
171
- .form-group input[type="checkbox"],
172
- .form-group input[type="radio"] {
173
- margin-right: 0.5rem;
174
- }
175
-
176
- .form-group label:has(input[type="checkbox"]) {
177
- display: flex;
178
- align-items: center;
179
- font-weight: normal;
180
- }
181
-
182
- .radio-group {
183
- display: flex;
184
- gap: 1.5rem;
185
- flex-wrap: wrap;
186
- }
187
-
188
- .radio-group label {
189
- display: flex;
190
- align-items: center;
191
- font-weight: normal;
192
- }
193
-
194
- .form-actions {
195
- display: flex;
196
- gap: 1rem;
197
- margin-top: 2rem;
198
- }
199
-
200
- .form-actions button {
201
- padding: 0.75rem 1.5rem;
202
- border: none;
203
- border-radius: 0.25rem;
204
- font-size: 1rem;
205
- cursor: pointer;
206
- }
207
-
208
- .form-actions button[type="submit"] {
209
- background-color: #0366d6;
210
- color: white;
211
- }
212
-
213
- .form-actions button[type="submit"]:hover {
214
- background-color: #0256c2;
215
- }
216
-
217
- .form-actions button[type="button"] {
218
- background-color: #6c757d;
219
- color: white;
220
- }
221
-
222
- .form-actions button[type="button"]:hover {
223
- background-color: #5a6268;
224
- }
225
-
226
- .form-result {
227
- margin-top: 2rem;
228
- padding: 1rem;
229
- background-color: #f8f9fa;
230
- border-radius: 0.25rem;
231
- border: 1px solid #dee2e6;
232
- }
233
-
234
- .form-result h3 {
235
- margin-top: 0;
236
- margin-bottom: 1rem;
237
- }
238
-
239
- .form-result pre {
240
- margin: 0;
241
- padding: 1rem;
242
- background-color: white;
243
- border-radius: 0.25rem;
244
- overflow-x: auto;
245
- }
246
-
247
- @media (prefers-color-scheme: dark) {
248
- .form-group input[type="text"],
249
- .form-group input[type="email"],
250
- .form-group select,
251
- .form-group textarea {
252
- background-color: #333;
253
- border-color: #555;
254
- color: #fff;
255
- }
256
-
257
- .form-result {
258
- background-color: #2d2d2d;
259
- border-color: #444;
260
- }
261
-
262
- .form-result pre {
263
- background-color: #1a1a1a;
264
- color: #fff;
265
- }
266
- }
267
- </style>
268
-
249
+ </script>
@@ -1,11 +1,15 @@
1
1
  <template>
2
2
  <Section title = "Welcome" classes = "">
3
3
  <template #toolbar>
4
+ <button @click="toggleSidebarEnabled" :class="sidebarEnabled ? 'neutral' : 'good'">
5
+ <HugeiconsIcon :icon="Menu01Icon" width="1em" height="1em" />
6
+ {{ sidebarEnabled ? 'Disable Sidebar' : 'Enable Sidebar' }}
7
+ </button>
8
+ <button @click="toggleBrandingEnabled" :class="brandingEnabled ? 'neutral' : 'good'">
9
+ <HugeiconsIcon :icon="HighlighterIcon" width="1em" height="1em" />
10
+ {{ brandingEnabled ? 'Hide Logo & Title' : 'Show Logo & Title' }}
11
+ </button>
4
12
  <div style="display: flex; gap: 1rem; align-items: center;">
5
- <label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer;">
6
- <input type="checkbox" :checked="sidebarEnabled" @change="toggleSidebarEnabled" />
7
- <span>Enable Sidebar</span>
8
- </label>
9
13
  <label style="display: flex; align-items: center; gap: 0.5rem; cursor: pointer;">
10
14
  <input type="checkbox" :checked="quickSearchEnabled" @change="toggleQuickSearchEnabled" />
11
15
  <span>Enable QuickSearch</span>
@@ -17,12 +21,12 @@
17
21
  </div>
18
22
  </template>
19
23
  <p>
20
- Welcome to Femtocrank, a web-based tool for analyzing and visualizing the performance of your code.
21
- To get started, you can either upload a file or paste your code directly into the editor.
24
+ Welcome to <strong>PicoCrank</strong>! This is a flexible example application to showcase a modular Vue 3 UI with a focus on ease of navigation, live UI controls, and modern design elements. Use the toolbar above to interactively enable or disable interface features like the sidebar, branding, QuickSearch, and the top navigation bar.
22
25
  </p>
23
26
  <p>
24
- For more information on how to use Femtocrank, please refer to the <a href = "/docs">documentation</a>.
27
+ Explore the sections below to see reusable components in action, including toolbars, buttons, and layout options. PicoCrank is designed to be a starting point for your own rapid Vue projects&mdash;inspect the code and try customizing the UI!
25
28
  </p>
29
+
26
30
  </Section>
27
31
 
28
32
  <Section title = "Lorum" id = "lorem">
@@ -93,9 +97,11 @@
93
97
  import { HighlighterIcon } from '@hugeicons/core-free-icons';
94
98
  import { Menu01Icon } from '@hugeicons/core-free-icons';
95
99
 
96
- // Inject sidebar, QuickSearch, and TopBar state and toggle functions from App.vue
100
+ // Inject sidebar and branding state and toggle functions from App.vue
97
101
  const sidebarEnabled = inject('sidebarEnabled');
98
102
  const toggleSidebarEnabled = inject('toggleSidebarEnabled');
103
+ const brandingEnabled = inject('brandingEnabled');
104
+ const toggleBrandingEnabled = inject('toggleBrandingEnabled');
99
105
  const quickSearchEnabled = inject('quickSearchEnabled');
100
106
  const toggleQuickSearchEnabled = inject('toggleQuickSearchEnabled');
101
107
  const topBarEnabled = inject('topBarEnabled');